From ec486185739a32a6dc1f96e3b70eee940cf1fa4f Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Fri, 13 Mar 2009 17:13:48 +0000 Subject: [PATCH] Initial import on SourceForge SVN:code[2] --- application/templates/audit_category.html | 12 + business/ChangeMgmt.php | 284 + business/Changes-04-Sep-2007.php | 32 + business/KEDB.php | 165 + business/ServiceMgmt.business.php | 259 + business/business_itopbegins.class.inc.php | 261 + business/business_test.class.inc.php | 372 ++ business/data.samples.inc.php | 4845 +++++++++++++++++ business/incident.business.php | 367 ++ business/itop.business.class.inc.php | 1633 ++++++ business/templates/Circuits.html | 12 + business/templates/application.html | 19 + business/templates/change.html | 17 + business/templates/contract.html | 18 + business/templates/default.html | 8 + business/templates/document.html | 13 + business/templates/group.html | 16 + business/templates/interface.html | 14 + business/templates/location.html | 25 + business/templates/network.device.html | 20 + business/templates/pc.html | 24 + business/templates/person.html | 18 + business/templates/server.html | 24 + business/templates/service.html | 13 + business/templates/software.html | 13 + business/templates/team.html | 21 + business/templates/ticket.html | 21 + business/test_farm.class.inc.php | 272 + config-dist.php | 38 + config-test-farm.php | 35 + config-test-mymodel.php | 36 + core/MyHelpers.class.inc.php | 383 ++ core/archive.class.inc.php | 323 ++ core/attributedef.class.inc.php | 989 ++++ core/cmdbchange.class.inc.php | 44 + core/cmdbchangeop.class.inc.php | 165 + core/cmdbobject.class.inc.php | 424 ++ core/cmdbsource.class.inc.php | 386 ++ core/config.class.inc.php | 170 + core/coreexception.class.inc.php | 52 + core/data.generator.class.inc.php | 362 ++ core/dbobject.class.php | 791 +++ core/dbobjectsearch.class.php | 967 ++++ core/dbobjectset.class.php | 255 + core/expression.class.inc.php | 431 ++ core/filterdef.class.inc.php | 296 + core/metamodel.class.php | 2675 +++++++++ core/oql/build.cmd | 3 + core/oql/oql-lexer.php | 522 ++ core/oql/oql-lexer.plex | 305 ++ core/oql/oql-parser.php | 1613 ++++++ core/oql/oql-parser.y | 213 + core/oql/oqlexception.class.inc.php | 38 + core/oql/oqlinterpreter.class.inc.php | 55 + core/oql/oqlquery.class.inc.php | 106 + core/sqlquery.class.inc.php | 399 ++ core/stimulus.class.inc.php | 59 + core/test.class.inc.php | 430 ++ core/userrights.class.inc.php | 205 + core/valuesetdef.class.inc.php | 238 + css/blue_green.css | 222 + css/date.picker.css | 117 + css/default.css | 165 + css/jqModal.css | 40 + css/jquery.autocomplete.css | 46 + css/jquery.tabs-ie.css | 15 + css/jquery.tabs.css | 76 + css/jquery.treeview.css | 47 + css/light-grey.css | 633 +++ images/Resize of Resize of erwanIncidents.jpg | Bin 0 -> 559 bytes images/Resize of Resize of erwanNetwork.jpg | Bin 0 -> 764 bytes images/Resize of Resize of erwanPC.jpg | Bin 0 -> 866 bytes images/Resize of erwanBuidling.jpg | Bin 0 -> 976 bytes images/Resize of erwanBuilding.jpg | Bin 0 -> 853 bytes images/Resize of erwanDocument.jpg | Bin 0 -> 883 bytes images/Resize of erwanIncidents.jpg | Bin 0 -> 859 bytes images/Resize of erwanNetwork.jpg | Bin 0 -> 1317 bytes images/Resize of erwanPC.jpg | Bin 0 -> 823 bytes images/Thumbs.db | Bin 0 -> 187392 bytes images/WanLinks.jpg | Bin 0 -> 3908 bytes images/actions_left.png | Bin 0 -> 205 bytes images/actions_right.png | Bin 0 -> 283 bytes images/bandeau2.gif | Bin 0 -> 1222 bytes images/bandeau3.gif | Bin 0 -> 132 bytes images/blue-corner.gif | Bin 0 -> 309 bytes images/bomb.jpg | Bin 0 -> 4145 bytes images/bomb.png | Bin 0 -> 8543 bytes images/calendar.png | Bin 0 -> 1091 bytes images/charts.swf | Bin 0 -> 29627 bytes images/charts_library/arno.swf | Bin 0 -> 6541 bytes images/charts_library/arst.swf | Bin 0 -> 6799 bytes images/charts_library/brfl.swf | Bin 0 -> 6848 bytes images/charts_library/brno.swf | Bin 0 -> 7004 bytes images/charts_library/brst.swf | Bin 0 -> 6854 bytes images/charts_library/cl3d.swf | Bin 0 -> 10125 bytes images/charts_library/clfl.swf | Bin 0 -> 6613 bytes images/charts_library/clno.swf | Bin 0 -> 6632 bytes images/charts_library/clp3.swf | Bin 0 -> 10106 bytes images/charts_library/cls3.swf | Bin 0 -> 10165 bytes images/charts_library/clst.swf | Bin 0 -> 6655 bytes images/charts_library/cnno.swf | Bin 0 -> 6801 bytes images/charts_library/lnno.swf | Bin 0 -> 7239 bytes images/charts_library/mxno.swf | Bin 0 -> 8736 bytes images/charts_library/pi3d.swf | Bin 0 -> 8592 bytes images/charts_library/pino.swf | Bin 0 -> 6152 bytes images/charts_library/pono.swf | Bin 0 -> 8178 bytes images/charts_library/scno.swf | Bin 0 -> 7209 bytes images/clean.png | Bin 0 -> 8714 bytes images/connect_to_network.png | Bin 0 -> 15254 bytes images/contacts.gif | Bin 0 -> 1057 bytes images/contacts_big.gif | Bin 0 -> 4586 bytes images/database exi.png | Bin 0 -> 14728 bytes images/database.png | Bin 0 -> 13514 bytes images/device.gif | Bin 0 -> 1070 bytes images/devices_big.gif | Bin 0 -> 4142 bytes images/documents.jpg | Bin 0 -> 7871 bytes images/drawer-handle.gif | Bin 0 -> 318 bytes images/erwanBuilding.jpg | Bin 0 -> 848 bytes images/erwanContracts.jpg | Bin 0 -> 1830 bytes images/erwanContracts2.jpg | Bin 0 -> 3298 bytes images/erwanContracts3.jpg | Bin 0 -> 2609 bytes images/erwanDocument.jpg | Bin 0 -> 887 bytes images/erwanIncidents.jpg | Bin 0 -> 861 bytes images/erwanMobilePhones.jpg | Bin 0 -> 2569 bytes images/erwanNetwork.jpg | Bin 0 -> 766 bytes images/erwanPC.jpg | Bin 0 -> 828 bytes images/erwanServices.jpg | Bin 0 -> 2839 bytes images/erwanTask.jpg | Bin 0 -> 2914 bytes images/erwanTools.jpg | Bin 0 -> 2247 bytes images/folder_documents.png | Bin 0 -> 11783 bytes images/green-corner.png | Bin 0 -> 287 bytes images/green-header.gif | Bin 0 -> 120 bytes images/green-square.gif | Bin 0 -> 56 bytes images/grey-header.gif | Bin 0 -> 122 bytes images/hgrabber2.gif | Bin 0 -> 217 bytes images/hgrabber2_active.gif | Bin 0 -> 220 bytes images/home.gif | Bin 0 -> 988 bytes images/iTop.gif | Bin 0 -> 3681 bytes images/iTop2.gif | Bin 0 -> 3765 bytes images/imageChange.gif | Bin 0 -> 4227 bytes images/imageChange.png | Bin 0 -> 2107 bytes images/indicator.gif | Bin 0 -> 1553 bytes images/indicator_arrows.gif | Bin 0 -> 729 bytes images/kservices-big.png | Bin 0 -> 19890 bytes images/laptop_pcmcia.png | Bin 0 -> 15250 bytes images/left-border.gif | Bin 0 -> 83 bytes images/location.gif | Bin 0 -> 998 bytes images/magnifier.gif | Bin 0 -> 534 bytes images/messagebox_warning.png | Bin 0 -> 7104 bytes images/mini-arrow-green-open.gif | Bin 0 -> 53 bytes images/mini-arrow-green.gif | Bin 0 -> 54 bytes images/minus.gif | Bin 0 -> 139 bytes images/network-server.png | Bin 0 -> 9234 bytes images/open-flash-chart.swf | Bin 0 -> 263109 bytes images/orange-header.gif | Bin 0 -> 122 bytes images/plus.gif | Bin 0 -> 142 bytes images/red-arrow.gif | Bin 0 -> 56 bytes images/red-header.gif | Bin 0 -> 122 bytes images/settings.gif | Bin 0 -> 256 bytes images/software.jpg | Bin 0 -> 2186 bytes images/starthere.png | Bin 0 -> 14272 bytes images/std_view.gif | Bin 0 -> 571 bytes images/stop.png | Bin 0 -> 9678 bytes images/tab-topleft.gif | Bin 0 -> 46 bytes images/tab.png | Bin 0 -> 593 bytes images/tar.png | Bin 0 -> 20427 bytes images/tv-collapsable-last.gif | Bin 0 -> 85 bytes images/tv-collapsable.gif | Bin 0 -> 781 bytes images/tv-expandable-last.gif | Bin 0 -> 89 bytes images/tv-expandable.gif | Bin 0 -> 787 bytes images/tv-item-last.gif | Bin 0 -> 65 bytes images/tv-item.gif | Bin 0 -> 750 bytes images/users2-big.png | Bin 0 -> 11703 bytes images/vgrabber2.gif | Bin 0 -> 381 bytes images/vgrabber2_active.gif | Bin 0 -> 258 bytes images/vsplitter-grey.gif | Bin 0 -> 59 bytes images/wan-mid.gif | Bin 0 -> 547 bytes images/wan.gif | Bin 0 -> 262 bytes images/wizActiveStepLeft.gif | Bin 0 -> 362 bytes images/wizActiveStepRight.gif | Bin 0 -> 501 bytes images/wizArrow.gif | Bin 0 -> 155 bytes images/wizStepLeft.gif | Bin 0 -> 217 bytes images/wizStepRight.gif | Bin 0 -> 425 bytes images/zoom.gif | Bin 0 -> 275 bytes index.php | 53 + js/LinksWidget.js | 112 + js/date.js | 467 ++ js/dimensions.js | 317 ++ js/forms-json-utils.js | 106 + js/hovertip.js | 458 ++ js/jqModal.js | 67 + js/jquery.autocomplete.js | 513 ++ js/jquery.bgiframe.js | 49 + js/jquery.blockUI.js | 312 ++ js/jquery.date.picker.js | 1056 ++++ js/jquery.dimensions.js | 308 ++ js/jquery.history_remote.pack.js | 1 + js/jquery.jdMenu.js | 435 ++ js/jquery.latest.js | 3549 ++++++++++++ js/jquery.pack.js | 1 + js/jquery.tablehover.js | 426 ++ js/jquery.tablesorter.min.js | 2 + js/jquery.tabs-ie.css | 15 + js/jquery.tabs.pack.js | 1 + js/jquery.treeview.js | 223 + js/json.js | 473 ++ js/json/json2.js | 461 ++ js/splitter.js | 180 + js/swfobject.js | 5 + js/themes/dark/dark.css | 11 + js/themes/dark/dark.form.css | 192 + js/themes/dark/dark.form.png | Bin 0 -> 12308 bytes js/themes/dark/dark.menu.css | 9 + js/themes/dark/dark.modal.css | 93 + js/themes/dark/dark.tabs.css | 73 + js/themes/dark/dark.tree.css | 61 + js/themes/flora/flora.accordion.css | 12 + js/themes/flora/flora.all.css | 9 + js/themes/flora/flora.calendar.css | 167 + js/themes/flora/flora.css | 2 + js/themes/flora/flora.dialog.css | 86 + js/themes/flora/flora.menu.css | 8 + js/themes/flora/flora.resizable.css | 20 + js/themes/flora/flora.shadow.css | 33 + js/themes/flora/flora.slider.css | 8 + js/themes/flora/flora.tablesorter.css | 40 + js/themes/flora/flora.tabs.css | 80 + js/themes/flora/i/Thumbs.db | Bin 0 -> 39424 bytes js/themes/flora/i/accordion-left-act.png | Bin 0 -> 249 bytes js/themes/flora/i/accordion-left-over.png | Bin 0 -> 174 bytes js/themes/flora/i/accordion-left.png | Bin 0 -> 174 bytes js/themes/flora/i/accordion-middle-act.png | Bin 0 -> 148 bytes js/themes/flora/i/accordion-middle-over.png | Bin 0 -> 122 bytes js/themes/flora/i/accordion-middle.png | Bin 0 -> 122 bytes js/themes/flora/i/accordion-right-act.png | Bin 0 -> 245 bytes js/themes/flora/i/accordion-right-over.png | Bin 0 -> 177 bytes js/themes/flora/i/accordion-right.png | Bin 0 -> 177 bytes js/themes/flora/i/asc.gif | Bin 0 -> 54 bytes js/themes/flora/i/bg.gif | Bin 0 -> 64 bytes js/themes/flora/i/desc.gif | Bin 0 -> 54 bytes js/themes/flora/i/dialog-e.gif | Bin 0 -> 440 bytes js/themes/flora/i/dialog-n.gif | Bin 0 -> 569 bytes js/themes/flora/i/dialog-ne.gif | Bin 0 -> 353 bytes js/themes/flora/i/dialog-nw.gif | Bin 0 -> 353 bytes js/themes/flora/i/dialog-s.gif | Bin 0 -> 434 bytes js/themes/flora/i/dialog-se.gif | Bin 0 -> 175 bytes js/themes/flora/i/dialog-sw.gif | Bin 0 -> 175 bytes js/themes/flora/i/dialog-title.gif | Bin 0 -> 238 bytes .../flora/i/dialog-titlebar-close-hover.png | Bin 0 -> 2927 bytes js/themes/flora/i/dialog-titlebar-close.png | Bin 0 -> 2880 bytes js/themes/flora/i/dialog-w.gif | Bin 0 -> 437 bytes js/themes/flora/i/menu-submenu.gif | Bin 0 -> 93 bytes js/themes/flora/i/resizable-e.gif | Bin 0 -> 338 bytes js/themes/flora/i/resizable-n.gif | Bin 0 -> 341 bytes js/themes/flora/i/resizable-ne.gif | Bin 0 -> 124 bytes js/themes/flora/i/resizable-nw.gif | Bin 0 -> 91 bytes js/themes/flora/i/resizable-s.gif | Bin 0 -> 341 bytes js/themes/flora/i/resizable-se.gif | Bin 0 -> 120 bytes js/themes/flora/i/resizable-sw.gif | Bin 0 -> 175 bytes js/themes/flora/i/resizable-w.gif | Bin 0 -> 339 bytes js/themes/flora/i/shadow.png | Bin 0 -> 3977 bytes js/themes/flora/i/slider-bg-1.png | Bin 0 -> 204 bytes js/themes/flora/i/slider-bg-2.png | Bin 0 -> 326 bytes js/themes/flora/i/slider-handle.gif | Bin 0 -> 176 bytes js/themes/flora/i/tabs.gif | Bin 0 -> 377 bytes js/themes/light/light.css | 11 + js/themes/light/light.form.css | 45 + js/themes/light/light.menu.css | 8 + js/themes/light/light.modal.css | 91 + js/themes/light/light.tabs.css | 71 + js/themes/light/light.tree.css | 61 + js/ui.accordion.js | 246 + js/ui.calendar.js | 871 +++ js/ui.dialog.js | 133 + js/ui.draggable.ext.js | 259 + js/ui.draggable.js | 182 + js/ui.droppable.ext.js | 25 + js/ui.droppable.js | 201 + js/ui.magnifier.js | 191 + js/ui.mouse.js | 253 + js/ui.resizable.js | 304 ++ js/ui.selectable.js | 116 + js/ui.shadow.js | 87 + js/ui.slider.js | 294 + js/ui.sortable.js | 262 + js/ui.tablesorter.js | 808 +++ js/ui.tabs.js | 445 ++ js/wizard.utils.js | 163 + js/wizardhelper.js | 108 + pages/ITopConsultant.php | 466 ++ pages/UI.php | 642 +++ pages/UniversalSearch.php | 142 + pages/advanced_search.php | 310 ++ pages/ajax.php | 40 + pages/ajax.render.php | 218 + pages/audit.php | 149 + pages/csvimport.php | 846 +++ pages/data_generator.php | 321 ++ pages/db_importer.php | 171 + pages/export.php | 64 + pages/graphviz.php | 75 + pages/incident.php | 757 +++ pages/index.php | 704 +++ pages/opensearch.xml | 8 + pages/php-ofc-library/JSON.php | 806 +++ pages/php-ofc-library/README.txt | 16 + pages/php-ofc-library/json_format.php | 86 + pages/php-ofc-library/ofc_area_base.php | 66 + pages/php-ofc-library/ofc_area_hollow.php | 10 + pages/php-ofc-library/ofc_area_line.php | 10 + pages/php-ofc-library/ofc_bar.php | 34 + pages/php-ofc-library/ofc_bar_3d.php | 31 + pages/php-ofc-library/ofc_bar_base.php | 41 + pages/php-ofc-library/ofc_bar_filled.php | 39 + pages/php-ofc-library/ofc_bar_glass.php | 33 + pages/php-ofc-library/ofc_bar_sketch.php | 23 + pages/php-ofc-library/ofc_bar_stack.php | 50 + pages/php-ofc-library/ofc_hbar.php | 64 + pages/php-ofc-library/ofc_line.php | 9 + pages/php-ofc-library/ofc_line_base.php | 70 + pages/php-ofc-library/ofc_line_dot.php | 33 + pages/php-ofc-library/ofc_line_hollow.php | 9 + pages/php-ofc-library/ofc_line_style.php | 11 + pages/php-ofc-library/ofc_pie.php | 109 + pages/php-ofc-library/ofc_radar_axis.php | 47 + .../php-ofc-library/ofc_radar_axis_labels.php | 15 + .../ofc_radar_spoke_labels.php | 15 + pages/php-ofc-library/ofc_scatter.php | 42 + pages/php-ofc-library/ofc_scatter_line.php | 27 + pages/php-ofc-library/ofc_shape.php | 25 + pages/php-ofc-library/ofc_title.php | 15 + pages/php-ofc-library/ofc_tooltip.php | 51 + pages/php-ofc-library/ofc_upload_image.php | 61 + pages/php-ofc-library/ofc_x_axis.php | 77 + pages/php-ofc-library/ofc_x_axis_label.php | 42 + pages/php-ofc-library/ofc_x_axis_labels.php | 34 + pages/php-ofc-library/ofc_x_legend.php | 15 + pages/php-ofc-library/ofc_y_axis.php | 17 + pages/php-ofc-library/ofc_y_axis_base.php | 56 + pages/php-ofc-library/ofc_y_axis_right.php | 6 + pages/php-ofc-library/ofc_y_legend.php | 15 + .../open-flash-chart-object.php | 109 + pages/php-ofc-library/open-flash-chart.php | 138 + pages/schema.php | 475 ++ pages/sibusql.php | 57 + pages/test.php | 126 + pages/testlist.inc.php | 842 +++ 347 files changed, 47666 insertions(+) create mode 100644 application/templates/audit_category.html create mode 100644 business/ChangeMgmt.php create mode 100644 business/Changes-04-Sep-2007.php create mode 100644 business/KEDB.php create mode 100644 business/ServiceMgmt.business.php create mode 100644 business/business_itopbegins.class.inc.php create mode 100644 business/business_test.class.inc.php create mode 100644 business/data.samples.inc.php create mode 100644 business/incident.business.php create mode 100644 business/itop.business.class.inc.php create mode 100644 business/templates/Circuits.html create mode 100644 business/templates/application.html create mode 100644 business/templates/change.html create mode 100644 business/templates/contract.html create mode 100644 business/templates/default.html create mode 100644 business/templates/document.html create mode 100644 business/templates/group.html create mode 100644 business/templates/interface.html create mode 100644 business/templates/location.html create mode 100644 business/templates/network.device.html create mode 100644 business/templates/pc.html create mode 100644 business/templates/person.html create mode 100644 business/templates/server.html create mode 100644 business/templates/service.html create mode 100644 business/templates/software.html create mode 100644 business/templates/team.html create mode 100644 business/templates/ticket.html create mode 100644 business/test_farm.class.inc.php create mode 100644 config-dist.php create mode 100644 config-test-farm.php create mode 100644 config-test-mymodel.php create mode 100644 core/MyHelpers.class.inc.php create mode 100644 core/archive.class.inc.php create mode 100644 core/attributedef.class.inc.php create mode 100644 core/cmdbchange.class.inc.php create mode 100644 core/cmdbchangeop.class.inc.php create mode 100644 core/cmdbobject.class.inc.php create mode 100644 core/cmdbsource.class.inc.php create mode 100644 core/config.class.inc.php create mode 100644 core/coreexception.class.inc.php create mode 100644 core/data.generator.class.inc.php create mode 100644 core/dbobject.class.php create mode 100644 core/dbobjectsearch.class.php create mode 100644 core/dbobjectset.class.php create mode 100644 core/expression.class.inc.php create mode 100644 core/filterdef.class.inc.php create mode 100644 core/metamodel.class.php create mode 100644 core/oql/build.cmd create mode 100644 core/oql/oql-lexer.php create mode 100644 core/oql/oql-lexer.plex create mode 100644 core/oql/oql-parser.php create mode 100644 core/oql/oql-parser.y create mode 100644 core/oql/oqlexception.class.inc.php create mode 100644 core/oql/oqlinterpreter.class.inc.php create mode 100644 core/oql/oqlquery.class.inc.php create mode 100644 core/sqlquery.class.inc.php create mode 100644 core/stimulus.class.inc.php create mode 100644 core/test.class.inc.php create mode 100644 core/userrights.class.inc.php create mode 100644 core/valuesetdef.class.inc.php create mode 100644 css/blue_green.css create mode 100644 css/date.picker.css create mode 100644 css/default.css create mode 100644 css/jqModal.css create mode 100644 css/jquery.autocomplete.css create mode 100644 css/jquery.tabs-ie.css create mode 100644 css/jquery.tabs.css create mode 100644 css/jquery.treeview.css create mode 100644 css/light-grey.css create mode 100644 images/Resize of Resize of erwanIncidents.jpg create mode 100644 images/Resize of Resize of erwanNetwork.jpg create mode 100644 images/Resize of Resize of erwanPC.jpg create mode 100644 images/Resize of erwanBuidling.jpg create mode 100644 images/Resize of erwanBuilding.jpg create mode 100644 images/Resize of erwanDocument.jpg create mode 100644 images/Resize of erwanIncidents.jpg create mode 100644 images/Resize of erwanNetwork.jpg create mode 100644 images/Resize of erwanPC.jpg create mode 100644 images/Thumbs.db create mode 100644 images/WanLinks.jpg create mode 100644 images/actions_left.png create mode 100644 images/actions_right.png create mode 100644 images/bandeau2.gif create mode 100644 images/bandeau3.gif create mode 100644 images/blue-corner.gif create mode 100644 images/bomb.jpg create mode 100644 images/bomb.png create mode 100644 images/calendar.png create mode 100644 images/charts.swf create mode 100644 images/charts_library/arno.swf create mode 100644 images/charts_library/arst.swf create mode 100644 images/charts_library/brfl.swf create mode 100644 images/charts_library/brno.swf create mode 100644 images/charts_library/brst.swf create mode 100644 images/charts_library/cl3d.swf create mode 100644 images/charts_library/clfl.swf create mode 100644 images/charts_library/clno.swf create mode 100644 images/charts_library/clp3.swf create mode 100644 images/charts_library/cls3.swf create mode 100644 images/charts_library/clst.swf create mode 100644 images/charts_library/cnno.swf create mode 100644 images/charts_library/lnno.swf create mode 100644 images/charts_library/mxno.swf create mode 100644 images/charts_library/pi3d.swf create mode 100644 images/charts_library/pino.swf create mode 100644 images/charts_library/pono.swf create mode 100644 images/charts_library/scno.swf create mode 100644 images/clean.png create mode 100644 images/connect_to_network.png create mode 100644 images/contacts.gif create mode 100644 images/contacts_big.gif create mode 100644 images/database exi.png create mode 100644 images/database.png create mode 100644 images/device.gif create mode 100644 images/devices_big.gif create mode 100644 images/documents.jpg create mode 100644 images/drawer-handle.gif create mode 100644 images/erwanBuilding.jpg create mode 100644 images/erwanContracts.jpg create mode 100644 images/erwanContracts2.jpg create mode 100644 images/erwanContracts3.jpg create mode 100644 images/erwanDocument.jpg create mode 100644 images/erwanIncidents.jpg create mode 100644 images/erwanMobilePhones.jpg create mode 100644 images/erwanNetwork.jpg create mode 100644 images/erwanPC.jpg create mode 100644 images/erwanServices.jpg create mode 100644 images/erwanTask.jpg create mode 100644 images/erwanTools.jpg create mode 100644 images/folder_documents.png create mode 100644 images/green-corner.png create mode 100644 images/green-header.gif create mode 100644 images/green-square.gif create mode 100644 images/grey-header.gif create mode 100644 images/hgrabber2.gif create mode 100644 images/hgrabber2_active.gif create mode 100644 images/home.gif create mode 100644 images/iTop.gif create mode 100644 images/iTop2.gif create mode 100644 images/imageChange.gif create mode 100644 images/imageChange.png create mode 100644 images/indicator.gif create mode 100644 images/indicator_arrows.gif create mode 100644 images/kservices-big.png create mode 100644 images/laptop_pcmcia.png create mode 100644 images/left-border.gif create mode 100644 images/location.gif create mode 100644 images/magnifier.gif create mode 100644 images/messagebox_warning.png create mode 100644 images/mini-arrow-green-open.gif create mode 100644 images/mini-arrow-green.gif create mode 100644 images/minus.gif create mode 100644 images/network-server.png create mode 100644 images/open-flash-chart.swf create mode 100644 images/orange-header.gif create mode 100644 images/plus.gif create mode 100644 images/red-arrow.gif create mode 100644 images/red-header.gif create mode 100644 images/settings.gif create mode 100644 images/software.jpg create mode 100644 images/starthere.png create mode 100644 images/std_view.gif create mode 100644 images/stop.png create mode 100644 images/tab-topleft.gif create mode 100644 images/tab.png create mode 100644 images/tar.png create mode 100644 images/tv-collapsable-last.gif create mode 100644 images/tv-collapsable.gif create mode 100644 images/tv-expandable-last.gif create mode 100644 images/tv-expandable.gif create mode 100644 images/tv-item-last.gif create mode 100644 images/tv-item.gif create mode 100644 images/users2-big.png create mode 100644 images/vgrabber2.gif create mode 100644 images/vgrabber2_active.gif create mode 100644 images/vsplitter-grey.gif create mode 100644 images/wan-mid.gif create mode 100644 images/wan.gif create mode 100644 images/wizActiveStepLeft.gif create mode 100644 images/wizActiveStepRight.gif create mode 100644 images/wizArrow.gif create mode 100644 images/wizStepLeft.gif create mode 100644 images/wizStepRight.gif create mode 100644 images/zoom.gif create mode 100644 index.php create mode 100644 js/LinksWidget.js create mode 100644 js/date.js create mode 100644 js/dimensions.js create mode 100644 js/forms-json-utils.js create mode 100644 js/hovertip.js create mode 100644 js/jqModal.js create mode 100644 js/jquery.autocomplete.js create mode 100644 js/jquery.bgiframe.js create mode 100644 js/jquery.blockUI.js create mode 100644 js/jquery.date.picker.js create mode 100644 js/jquery.dimensions.js create mode 100644 js/jquery.history_remote.pack.js create mode 100644 js/jquery.jdMenu.js create mode 100644 js/jquery.latest.js create mode 100644 js/jquery.pack.js create mode 100644 js/jquery.tablehover.js create mode 100644 js/jquery.tablesorter.min.js create mode 100644 js/jquery.tabs-ie.css create mode 100644 js/jquery.tabs.pack.js create mode 100644 js/jquery.treeview.js create mode 100644 js/json.js create mode 100644 js/json/json2.js create mode 100644 js/splitter.js create mode 100644 js/swfobject.js create mode 100644 js/themes/dark/dark.css create mode 100644 js/themes/dark/dark.form.css create mode 100644 js/themes/dark/dark.form.png create mode 100644 js/themes/dark/dark.menu.css create mode 100644 js/themes/dark/dark.modal.css create mode 100644 js/themes/dark/dark.tabs.css create mode 100644 js/themes/dark/dark.tree.css create mode 100644 js/themes/flora/flora.accordion.css create mode 100644 js/themes/flora/flora.all.css create mode 100644 js/themes/flora/flora.calendar.css create mode 100644 js/themes/flora/flora.css create mode 100644 js/themes/flora/flora.dialog.css create mode 100644 js/themes/flora/flora.menu.css create mode 100644 js/themes/flora/flora.resizable.css create mode 100644 js/themes/flora/flora.shadow.css create mode 100644 js/themes/flora/flora.slider.css create mode 100644 js/themes/flora/flora.tablesorter.css create mode 100644 js/themes/flora/flora.tabs.css create mode 100644 js/themes/flora/i/Thumbs.db create mode 100644 js/themes/flora/i/accordion-left-act.png create mode 100644 js/themes/flora/i/accordion-left-over.png create mode 100644 js/themes/flora/i/accordion-left.png create mode 100644 js/themes/flora/i/accordion-middle-act.png create mode 100644 js/themes/flora/i/accordion-middle-over.png create mode 100644 js/themes/flora/i/accordion-middle.png create mode 100644 js/themes/flora/i/accordion-right-act.png create mode 100644 js/themes/flora/i/accordion-right-over.png create mode 100644 js/themes/flora/i/accordion-right.png create mode 100644 js/themes/flora/i/asc.gif create mode 100644 js/themes/flora/i/bg.gif create mode 100644 js/themes/flora/i/desc.gif create mode 100644 js/themes/flora/i/dialog-e.gif create mode 100644 js/themes/flora/i/dialog-n.gif create mode 100644 js/themes/flora/i/dialog-ne.gif create mode 100644 js/themes/flora/i/dialog-nw.gif create mode 100644 js/themes/flora/i/dialog-s.gif create mode 100644 js/themes/flora/i/dialog-se.gif create mode 100644 js/themes/flora/i/dialog-sw.gif create mode 100644 js/themes/flora/i/dialog-title.gif create mode 100644 js/themes/flora/i/dialog-titlebar-close-hover.png create mode 100644 js/themes/flora/i/dialog-titlebar-close.png create mode 100644 js/themes/flora/i/dialog-w.gif create mode 100644 js/themes/flora/i/menu-submenu.gif create mode 100644 js/themes/flora/i/resizable-e.gif create mode 100644 js/themes/flora/i/resizable-n.gif create mode 100644 js/themes/flora/i/resizable-ne.gif create mode 100644 js/themes/flora/i/resizable-nw.gif create mode 100644 js/themes/flora/i/resizable-s.gif create mode 100644 js/themes/flora/i/resizable-se.gif create mode 100644 js/themes/flora/i/resizable-sw.gif create mode 100644 js/themes/flora/i/resizable-w.gif create mode 100644 js/themes/flora/i/shadow.png create mode 100644 js/themes/flora/i/slider-bg-1.png create mode 100644 js/themes/flora/i/slider-bg-2.png create mode 100644 js/themes/flora/i/slider-handle.gif create mode 100644 js/themes/flora/i/tabs.gif create mode 100644 js/themes/light/light.css create mode 100644 js/themes/light/light.form.css create mode 100644 js/themes/light/light.menu.css create mode 100644 js/themes/light/light.modal.css create mode 100644 js/themes/light/light.tabs.css create mode 100644 js/themes/light/light.tree.css create mode 100644 js/ui.accordion.js create mode 100644 js/ui.calendar.js create mode 100644 js/ui.dialog.js create mode 100644 js/ui.draggable.ext.js create mode 100644 js/ui.draggable.js create mode 100644 js/ui.droppable.ext.js create mode 100644 js/ui.droppable.js create mode 100644 js/ui.magnifier.js create mode 100644 js/ui.mouse.js create mode 100644 js/ui.resizable.js create mode 100644 js/ui.selectable.js create mode 100644 js/ui.shadow.js create mode 100644 js/ui.slider.js create mode 100644 js/ui.sortable.js create mode 100644 js/ui.tablesorter.js create mode 100644 js/ui.tabs.js create mode 100644 js/wizard.utils.js create mode 100644 js/wizardhelper.js create mode 100644 pages/ITopConsultant.php create mode 100644 pages/UI.php create mode 100644 pages/UniversalSearch.php create mode 100644 pages/advanced_search.php create mode 100644 pages/ajax.php create mode 100644 pages/ajax.render.php create mode 100644 pages/audit.php create mode 100644 pages/csvimport.php create mode 100644 pages/data_generator.php create mode 100644 pages/db_importer.php create mode 100644 pages/export.php create mode 100644 pages/graphviz.php create mode 100644 pages/incident.php create mode 100644 pages/index.php create mode 100644 pages/opensearch.xml create mode 100644 pages/php-ofc-library/JSON.php create mode 100644 pages/php-ofc-library/README.txt create mode 100644 pages/php-ofc-library/json_format.php create mode 100644 pages/php-ofc-library/ofc_area_base.php create mode 100644 pages/php-ofc-library/ofc_area_hollow.php create mode 100644 pages/php-ofc-library/ofc_area_line.php create mode 100644 pages/php-ofc-library/ofc_bar.php create mode 100644 pages/php-ofc-library/ofc_bar_3d.php create mode 100644 pages/php-ofc-library/ofc_bar_base.php create mode 100644 pages/php-ofc-library/ofc_bar_filled.php create mode 100644 pages/php-ofc-library/ofc_bar_glass.php create mode 100644 pages/php-ofc-library/ofc_bar_sketch.php create mode 100644 pages/php-ofc-library/ofc_bar_stack.php create mode 100644 pages/php-ofc-library/ofc_hbar.php create mode 100644 pages/php-ofc-library/ofc_line.php create mode 100644 pages/php-ofc-library/ofc_line_base.php create mode 100644 pages/php-ofc-library/ofc_line_dot.php create mode 100644 pages/php-ofc-library/ofc_line_hollow.php create mode 100644 pages/php-ofc-library/ofc_line_style.php create mode 100644 pages/php-ofc-library/ofc_pie.php create mode 100644 pages/php-ofc-library/ofc_radar_axis.php create mode 100644 pages/php-ofc-library/ofc_radar_axis_labels.php create mode 100644 pages/php-ofc-library/ofc_radar_spoke_labels.php create mode 100644 pages/php-ofc-library/ofc_scatter.php create mode 100644 pages/php-ofc-library/ofc_scatter_line.php create mode 100644 pages/php-ofc-library/ofc_shape.php create mode 100644 pages/php-ofc-library/ofc_title.php create mode 100644 pages/php-ofc-library/ofc_tooltip.php create mode 100644 pages/php-ofc-library/ofc_upload_image.php create mode 100644 pages/php-ofc-library/ofc_x_axis.php create mode 100644 pages/php-ofc-library/ofc_x_axis_label.php create mode 100644 pages/php-ofc-library/ofc_x_axis_labels.php create mode 100644 pages/php-ofc-library/ofc_x_legend.php create mode 100644 pages/php-ofc-library/ofc_y_axis.php create mode 100644 pages/php-ofc-library/ofc_y_axis_base.php create mode 100644 pages/php-ofc-library/ofc_y_axis_right.php create mode 100644 pages/php-ofc-library/ofc_y_legend.php create mode 100644 pages/php-ofc-library/open-flash-chart-object.php create mode 100644 pages/php-ofc-library/open-flash-chart.php create mode 100644 pages/schema.php create mode 100644 pages/sibusql.php create mode 100644 pages/test.php create mode 100644 pages/testlist.inc.php diff --git a/application/templates/audit_category.html b/application/templates/audit_category.html new file mode 100644 index 000000000..a45b00fcb --- /dev/null +++ b/application/templates/audit_category.html @@ -0,0 +1,12 @@ + + +$class$: pkey = $pkey$ + + + AuditRule: category_id = $pkey$ + + diff --git a/business/ChangeMgmt.php b/business/ChangeMgmt.php new file mode 100644 index 000000000..891f42e28 --- /dev/null +++ b/business/ChangeMgmt.php @@ -0,0 +1,284 @@ + "bizmodel,searchable", + "name" => "Change", + "description" => "Change ticket", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "ticket_status", + "reconc_keys" => array("title"), + "db_table" => "change_ticket", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/change.html", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"TicketID", "description"=>"Refence number ofr this change", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("title", array("label"=>"Title", "description"=>"Overview of the Change", "allowed_values"=>null, "sql"=>"title", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("type", array("label"=>"Change Type", "description"=>"Type of the Change", "allowed_values"=>new ValueSetEnum("Routine, Normal, Emergency"), "sql"=>"type", "default_value"=>"Routine", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("domain", array("label"=>"Domain", "description"=>"Domain for the Change", "allowed_values"=>new ValueSetEnum("Network,Server,Desktop,Application"), "sql"=>"domain", "default_value"=>"Desktop", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeString("reason", array("label"=>"Reason for change", "description"=>"Reason for the Change", "allowed_values"=>null, "sql"=>"reason", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("requestor_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Requestor", "description"=>"who is requesting this change", "allowed_values"=>null, "sql"=>"requestor_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("requestor_mail", array("label"=>"Requested by", "description"=>"mail of user requesting this change", "allowed_values"=>null, "extkey_attcode"=> 'requestor_id', "target_attcode"=>"email"))); + + + MetaModel::Init_AddAttribute(new AttributeExternalKey("customer_id", array("targetclass"=>"bizOrganization", "label"=>"Customer", "description"=>"who is impacted by the ticket", "allowed_values"=>null, "sql"=>"customer", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("customer_name", array("label"=>"Customer", "description"=>"Name of the customer impacted by this ticket", "allowed_values"=>null, "extkey_attcode"=> 'customer_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeEnum("ticket_status", array("label"=>"Status", "description"=>"Status of the ticket", "allowed_values"=>new ValueSetEnum("New, Validated,Rejected,PlannedScheduled,Approved,NotApproved,Implemented,Monitored, Closed"), "sql"=>"change_status", "default_value"=>"New", "is_null_allowed"=>false, "depends_on"=>array()))); + // SetPossibleValues("status",array("Open","Monitored","Closed")); + + MetaModel::Init_AddAttribute(new AttributeDate("creation_date", array("label"=>"Creation date", "description"=>"Change creation date", "allowed_values"=>null, "sql"=>"creation_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + // définir une date de défaut à maintenant, alias creation ou modification du ticket + MetaModel::Init_AddAttribute(new AttributeDate("last_update", array("label"=>"Last update", "description"=>"last time the Ticket was modified", "allowed_values"=>null, "sql"=>"last_update", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("start_date", array("label"=>"Start date", "description"=>"Time the change is expected to start", "allowed_values"=>null, "sql"=>"start_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("end_date", array("label"=>"End Date", "description"=>"Date when the change is supposed to end", "allowed_values"=>null, "sql"=>"end_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("close_date", array("label"=>"Closed Date", "description"=>"Date when the Ticket was closed", "allowed_values"=>null, "sql"=>"closed_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Risk Assessment", "description"=>"Impact of the change", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("workgroup_id", array("targetclass"=>"bizWorkgroup", "jointype"=> "", "label"=>"Workgroup", "description"=>"which workgroup is owning ticket", "allowed_values"=>null, "sql"=>"workgroup_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("workgroup_name", array("label"=>"Managed by Workgroup", "description"=>"name of workgroup managing the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'workgroup_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("agent_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Agent", "description"=>"who is managing the ticket", "allowed_values"=>null, "sql"=>"agent_id", "is_null_allowed"=>true, "depends_on"=>array('workgroup_id')))); + MetaModel::Init_AddAttribute(new AttributeExternalField("agent_name", array("label"=>"Managed by Agent", "description"=>"name of agent managing the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'agent_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("supervisorgroup_id", array("targetclass"=>"bizWorkgroup", "jointype"=> "", "label"=>"Supervisor group", "description"=>"which workgroup is supervising ticket", "allowed_values"=>null, "sql"=>"supervisorgroup_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("supervisorgroup_name", array("label"=>"Supervise by Workgroup", "description"=>"name of the group supervising the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'supervisorgroup_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("supervisor_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Supervisor", "description"=>"who is managing the ticket", "allowed_values"=>null, "sql"=>"supervisor_id", "is_null_allowed"=>true, "depends_on"=>array('supervisorgroup_id')))); + MetaModel::Init_AddAttribute(new AttributeExternalField("supervisor_name", array("label"=>"Managed by Supervisor", "description"=>"name of agent supervising the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'supervisor_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("managergroup_id", array("targetclass"=>"bizWorkgroup", "jointype"=> "", "label"=>"Manager group", "description"=>"which workgroup is approving ticket", "allowed_values"=>null, "sql"=>"managergroup_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("managergroup_name", array("label"=>"Approved by group", "description"=>"name of workgroup approving the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'managergroup_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("manager_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Manager", "description"=>"who is approving the ticket", "allowed_values"=>null, "sql"=>"manager_id", "is_null_allowed"=>true, "depends_on"=>array('managergroup_id')))); + MetaModel::Init_AddAttribute(new AttributeExternalField("manager_name", array("label"=>"Approved by Agent", "description"=>"name of agent approving the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'manager_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeEnum("outage", array("label"=>"Planned Outage", "description"=>"Flag to define if there is a planned outage", "allowed_values"=>new ValueSetEnum("Yes,No"), "sql"=>"outage", "default_value"=>"No", "is_null_allowed"=>false, "depends_on"=>array()))); + + + MetaModel::Init_AddAttribute(new AttributeText("change_request", array("label"=>"Change Request", "description"=>"Description of Change required", "allowed_values"=>null, "sql"=>"change_req", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("change_log", array("label"=>"Implementation log", "description"=>"List all action performed during the change", "allowed_values"=>null, "sql"=>"change_log", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("fallback", array("label"=>"Fallback plan", "description"=>"Instruction to come back to former situation", "allowed_values"=>null, "sql"=>"fallback", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("assignment_count", array("label"=>"Assignment Count", "description"=>"Number of times this ticket was assigned or reassigned", "allowed_values"=>null, "sql"=>"assignment_count", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("impacted_infra_manual", array("label"=>"Impacted Infrastructure", "description"=>"CIs that are impacted by this change", "linked_class"=>"lnkInfraChangeTicket", "ext_key_to_me"=>"ticket_id", "ext_key_to_remote"=>"infra_id", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array()))); + + //MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("title"); + MetaModel::Init_AddFilterFromAttribute("type"); + MetaModel::Init_AddFilterFromAttribute("domain"); + MetaModel::Init_AddFilterFromAttribute("customer_id"); + MetaModel::Init_AddFilterFromAttribute("requestor_id"); + MetaModel::Init_AddFilterFromAttribute("ticket_status"); + MetaModel::Init_AddFilterFromAttribute("creation_date"); + MetaModel::Init_AddFilterFromAttribute("start_date"); + MetaModel::Init_AddFilterFromAttribute("last_update"); + MetaModel::Init_AddFilterFromAttribute("end_date"); + MetaModel::Init_AddFilterFromAttribute("close_date"); + MetaModel::Init_AddFilterFromAttribute("workgroup_id"); + MetaModel::Init_AddFilterFromAttribute("workgroup_name"); + MetaModel::Init_AddFilterFromAttribute("supervisorgroup_id"); + MetaModel::Init_AddFilterFromAttribute("managergroup_id"); + MetaModel::Init_AddFilterFromAttribute("supervisor_id"); + MetaModel::Init_AddFilterFromAttribute("manager_id"); + MetaModel::Init_AddFilterFromAttribute("agent_id"); + MetaModel::Init_AddFilterFromAttribute("impact"); + MetaModel::Init_AddFilterFromAttribute("assignment_count"); + MetaModel::Init_AddFilterFromAttribute("outage"); + + // doit-on aussi ajouter un filtre sur les extfields lié à une extkey ? ici le name de l'agent? + + // Display lists + MetaModel::Init_SetZListItems('details', array('name','title', 'customer_id','type','domain','requestor_id','change_request','ticket_status', 'outage','impact', 'last_update', 'start_date','end_date', 'assignment_count', 'workgroup_id','agent_id','supervisorgroup_id','supervisor_id','managergroup_id','manager_id','change_log','fallback')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('name', 'title', 'customer_id', 'ticket_status','outage','start_date','type')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'title', 'customer_id', 'ticket_status','type', 'outage','requestor_id','workgroup_id','agent_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'title', 'customer_id', 'ticket_status','type', 'outage','workgroup_id','agent_id')); // Criteria of the advanced search form + + // State machine + MetaModel::Init_DefineState("New", array("label"=>"New (Unassigned)", "description"=>"Newly created ticket", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY,'customer_id' => OPT_ATT_MANDATORY, 'title' => OPT_ATT_MANDATORY, 'reason' => OPT_ATT_MANDATORY, 'impacted_infra_manual' => OPT_ATT_MANDATORY, + 'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN))); + MetaModel::Init_DefineState("Validated", array("label"=>"Validated", "description"=>"Ticket is approved", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY, 'customer_id' => OPT_ATT_READONLY,'assignment_count' => OPT_ATT_READONLY,'managergroup_id' => OPT_ATT_MANDATORY, 'supervisorgroup_id' => OPT_ATT_MANDATORY))); + MetaModel::Init_DefineState("Rejected", array("label"=>"Rejected", "description"=>"This ticket is not approved", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY, 'customer_id' => OPT_ATT_READONLY,'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN))); + MetaModel::Init_DefineState("PlannedScheduled", array("label"=>"Planned&Scheduled", "description"=>"Evaluation is done for this change", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY, 'customer_id' => OPT_ATT_READONLY,'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_MANDATORY, 'impact' => OPT_ATT_MANDATORY, 'workgroup_id' => OPT_ATT_MANDATORY, 'change_log' => OPT_ATT_MUSTCHANGE,'fallback' => OPT_ATT_MANDATORY))); + MetaModel::Init_DefineState("Approved", array("label"=>"Approved", "description"=>"Ticket is approved by CAB", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY,'customer_id' => OPT_ATT_READONLY, 'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN))); + MetaModel::Init_DefineState("NotApproved", array("label"=>"Not Approved", "description"=>"Ticket has not been approved by CAB", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY,'customer_id' => OPT_ATT_READONLY, 'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN))); + MetaModel::Init_DefineState("Implemented", array("label"=>"Implementation", "description"=>"Work is in progress for this ticket", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY,'customer_id' => OPT_ATT_READONLY, 'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN))); + MetaModel::Init_DefineState("Monitored", array("label"=>"Monitored", "description"=>"Change performed is now monitored", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY,'customer_id' => OPT_ATT_READONLY,'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN))); + MetaModel::Init_DefineState("Closed", array("label"=>"Closed", "description"=>"Ticket is closed", "attribute_inherit"=>null, "attribute_list"=>array('customer_id' => OPT_ATT_READONLY,"workgroup_id"=>OPT_ATT_MANDATORY, "agent_id"=>OPT_ATT_MANDATORY))); + + MetaModel::Init_DefineStimulus("ev_validate", new StimulusUserAction(array("label"=>"Validate this change", "description"=>"Make sure it is a valid change request"))); + MetaModel::Init_DefineStimulus("ev_reject", new StimulusUserAction(array("label"=>"Reject this change", "description"=>"This change request is rejected because it is a non valid one"))); + MetaModel::Init_DefineStimulus("ev_reopen", new StimulusUserAction(array("label"=>"Modify this change", "description"=>"Update change request to make it valid"))); + MetaModel::Init_DefineStimulus("ev_plan", new StimulusUserAction(array("label"=>"Plan this change", "description"=>"Plan and Schedule this change for validation"))); + MetaModel::Init_DefineStimulus("ev_approve", new StimulusUserAction(array("label"=>"Approve this change", "description"=>"This change is approved by CAB"))); + MetaModel::Init_DefineStimulus("ev_replan", new StimulusUserAction(array("label"=>"Update planning and schedule", "description"=>"Modify Plan and Schedule in order to have this change re-validated"))); + MetaModel::Init_DefineStimulus("ev_notapprove", new StimulusUserAction(array("label"=>"Not approve this change", "description"=>"This change is not approved by CAB"))); + MetaModel::Init_DefineStimulus("ev_implement", new StimulusUserAction(array("label"=>"Implement this change", "description"=>"Implementation pahse for current change"))); + MetaModel::Init_DefineStimulus("ev_monitor", new StimulusUserAction(array("label"=>"Monitor this change", "description"=>"Starting monitoring period for this change"))); + MetaModel::Init_DefineStimulus("ev_finish", new StimulusUserAction(array("label"=>"Close change", "description"=>"Change is done, and can be closed"))); + + MetaModel::Init_DefineTransition("New", "ev_validate", array("target_state"=>"Validated", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("New", "ev_reject", array("target_state"=>"Rejected", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Rejected", "ev_reopen", array("target_state"=>"New", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Validated", "ev_plan", array("target_state"=>"PlannedScheduled", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("PlannedScheduled", "ev_approve", array("target_state"=>"Approved", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("PlannedScheduled", "ev_notapprove", array("target_state"=>"NotApproved", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("NotApproved", "ev_replan", array("target_state"=>"PlannedScheduled", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Approved", "ev_implement", array("target_state"=>"Implemented", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Implemented", "ev_monitor", array("target_state"=>"Monitored", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Implemented", "ev_finish", array("target_state"=>"Closed", "actions"=>array('SetLastUpDate'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Monitored", "ev_finish", array("target_state"=>"Closed", "actions"=>array(), "user_restriction"=>null)); + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('customer_id', $oGenerator->GetOrganizationId()); + $this->Set('title', $oGenerator->GenerateString("enum(Site,Server,Line)| |enum(is down,is flip-flopping,is not responding)")); + $this->Set('agent_id', $oGenerator->GenerateKey("bizPerson", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('ticket_status', $oGenerator->GenerateString("enum(Open,Closed,Closed,Monitored)")); + $this->Set('start_date', $oGenerator->GenerateString("2007-|number(07-12)|-|number(01-30)| |number(07-12)|:|number(00-59)|:|number(00-59)")); + $this->Set('last_update', $oGenerator->GenerateString("2007-|number(07-12)|-|number(01-30)| |number(07-12)|:|number(00-59)|:|number(00-59)")); + $this->Set('end_date', $oGenerator->GenerateString("2007-|number(07-12)|-|number(01-30)| |number(07-12)|:|number(00-59)|:|number(00-59)")); + } + + + + // State machine actions + public function IncrementAssignmentCount($sStimulusCode) + { + $this->Set('assignment_count', $this->Get('assignment_count') + 1); + return true; + } + + public function SetClosureDate($sStimulusCode) + { + $this->Set('end_date', time()); + return true; + } + public function SetLastUpDate($sStimulusCode) + { + $this->Set('last_update', time()); + return true; + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Infra and a Change Ticket +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkInfraChangeTicket extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Infra Change Ticket", + "description" => "Infra impacted by a Change ticket", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "impact", // ???? + "state_attcode" => "", + "reconc_keys" => array("impact"), // ???? + "db_table" => "infra_changeticket", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("infra_id", array("targetclass"=>"logInfra", "jointype"=> '', "label"=>"Infrastructure", "description"=>"The infrastructure impacted", "allowed_values"=>null, "sql"=>"infra_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_name", array("label"=>"Infrastructure name", "description"=>"Name of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("ticket_id", array("targetclass"=>"bizChangeTicket", "jointype"=> '', "label"=>"Ticket #", "description"=>"Ticket number", "allowed_values"=>null, "sql"=>"ticket_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ticket_name", array("label"=>"Ticket name", "description"=>"Name of the ticket", "allowed_values"=>null, "extkey_attcode"=> 'ticket_id', "target_attcode"=>"title"))); + MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Impact", "description"=>"Level of impact of the infra by the related ticket", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("infra_id"); + MetaModel::Init_AddFilterFromAttribute("ticket_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('infra_id', 'ticket_id', 'impact')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('infra_id', 'ticket_id', 'impact')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('infra_id', 'ticket_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('infra_id', 'ticket_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('infra_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('ticket_id', $oGenerator->GenerateKey("bizIncidentTicket", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('impact', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } +} +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any contact and a Contract +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkContactChange extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "ContactChangeLink", + "description" => "Contact associated to a change", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "role", // ???? + "state_attcode" => "", + "reconc_keys" => array("role"), // ???? + "db_table" => "contact_change", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contact_id", array("targetclass"=>"bizContact", "jointype"=> '', "label"=>"Contact", "description"=>"The contact linked to contract", "allowed_values"=>null, "sql"=>"contact_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_mail", array("label"=>"Contact E-mail", "description"=>"Mail for the contact", "allowed_values"=>null, "extkey_attcode"=> 'contact_id', "target_attcode"=>"email"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("change_id", array("targetclass"=>"bizChangeTicket", "jointype"=> '', "label"=>"Change Ticket", "description"=>"Change ticket ID", "allowed_values"=>null, "sql"=>"change_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("change_number", array("label"=>"change number", "description"=>"Ticket number for this change", "allowed_values"=>null, "extkey_attcode"=> 'change_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("role", array("label"=>"Role", "description"=>"Role of this contact for this change", "allowed_values"=>null, "sql"=>"role", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("change_id"); + MetaModel::Init_AddFilterFromAttribute("contact_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('change_id', 'contact_id', 'role')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('change_id', 'contact_id', 'role')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('change_id', 'contact_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('change_id', 'contact_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('contract_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('contact_id', $oGenerator->GenerateKey("bizIncidentTicket", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('role', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } + +} + +?> diff --git a/business/Changes-04-Sep-2007.php b/business/Changes-04-Sep-2007.php new file mode 100644 index 000000000..e8097d75e --- /dev/null +++ b/business/Changes-04-Sep-2007.php @@ -0,0 +1,32 @@ +Changements principaux: +- la classe AbstractObject est sortie du biz model +- join_type remplacé par is_null_allowed (placé à la fin pour être + facile à retrouver) +- j'ai enlevé toute la classe logLocatedObject qui était en commentaire +- Enlevé 'address' de l'advanced search sur une location car ce n'est plus un critère de recherche possible (remplacé par country) +- Ajouté des critères de recherche sur bizCircuit +- Ajouté les ZList sur bizCircuit +- Ajouté les Zlist pour bizInterface +- Ajouté les Zlist pour lnkInfraInfra +- Ajouté les Zlist pour lnkInfraTicket + +Dans AbstractObject: désactivé l'affichage des contacts liés qui ne marche pas pour les tickets. + +Bug fix ? +- J'ai rajouté un blindage if (is_object($proposedValue) &&... dans AttributeDate::MakeRealValue mais je ne comprends pas d'où sort la classe DateTime... et pourtant il y en a... + +Améliorations: +- Ajouter une vérification des ZList (les attributs/critèresde recherche déclarés dans la liste existent-ils pour cet objet) + +Ne marche pas: +- Objets avec des clefs externes vides +- Enums !!!! + +Data Generator: +Organization '1' updated. +5 Location objects created. +19 PC objects created. +19 Network Device objects created. +42 Person objects created. +6 Incident objects created. +17 Infra Group objects created. +34 Infra Infra objects created. diff --git a/business/KEDB.php b/business/KEDB.php new file mode 100644 index 000000000..ec8057f32 --- /dev/null +++ b/business/KEDB.php @@ -0,0 +1,165 @@ + "bizmodel,searchable", + "name" => "Known Error", + "description" => "Error documented for a known issue", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("cust_id", "name"), // inherited attributes + "db_table" => "known_error", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/knownError.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"Name", "description"=>"Name to identify this error", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("cust_id", array("targetclass"=>"bizOrganization", "label"=>"Organization", "description"=>"Organization for this known error", "allowed_values"=>null, "sql"=>"cust_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("cust_name", array("label"=>"Organization", "description"=>"Company / Department owning this object", "allowed_values"=>null, "extkey_attcode"=> 'cust_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddAttribute(new AttributeText("symptom", array("label"=>"Symptom", "description"=>"Description of this error", "allowed_values"=>null, "sql"=>"symptom", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("root_cause", array("label"=>"Root cause", "description"=>"Original cause for this known error", "allowed_values"=>null, "sql"=>"rootcause", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("workaround", array("label"=>"Work around", "description"=>"Work around to fix this error", "allowed_values"=>null, "sql"=>"workaround", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("solution", array("label"=>"Solution", "description"=>"Description of this contract", "allowed_values"=>null, "sql"=>"solution", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeString("error_code", array("label"=>"Error Code", "description"=>"Key word to identify error", "allowed_values"=>null, "sql"=>"error_code", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("domain", array("label"=>"Domain", "description"=>"Domain for this known error, network, desktop, ...", "allowed_values"=>new ValueSetEnum("Network, Server, Application, Desktop"), "sql"=>"domain", "default_value"=>"Application", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("vendor", array("label"=>"Vendor", "description"=>"Vendor concerned by this known error", "allowed_values"=>null, "sql"=>"vendor", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("model", array("label"=>"Model", "description"=>"Model concerned by this known error, it may be an application, a device ...", "allowed_values"=>null, "sql"=>"model", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("version", array("label"=>"Version", "description"=>"Version related to model impacted by known error", "allowed_values"=>null, "sql"=>"version", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("cust_id"); + MetaModel::Init_AddFilterFromAttribute("cust_name"); + MetaModel::Init_AddFilterFromAttribute("error_code"); + MetaModel::Init_AddFilterFromAttribute("domain"); + + + + + + MetaModel::Init_SetZListItems('details', array('name', 'cust_id','error_code','domain','vendor','model','version', 'symptom','root_cause','workaround','solution')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'cust_id','error_code', 'symptom')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'error_code','domain')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'cust_id','error_code', 'error_code','symptom')); // Criteria of the advanced search form + + } + + // State machine actions + public function IncrementVersion($sStimulusCode) + { + $this->Set('version_number', $this->Get('version_number') + 1); + return true; + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Infra and a Known Error +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkInfraError extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "InfraErrorLinks", + "description" => "Infra related to a known error", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "", // ???? + "state_attcode" => "", + "reconc_keys" => array("infra_id","error_id"), // ???? + "db_table" => "infra_error_links", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("infra_id", array("targetclass"=>"logInfra", "jointype"=> '', "label"=>"Infrastructure", "description"=>"The infrastructure impacted", "allowed_values"=>null, "sql"=>"infra_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_name", array("label"=>"Infrastructure name", "description"=>"Name of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_status", array("label"=>"Status", "description"=>"Status of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"status"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("error_id", array("targetclass"=>"bizKnownError", "jointype"=> '', "label"=>"Error name", "description"=>"Error id", "allowed_values"=>null, "sql"=>"error_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("error_name", array("label"=>"Error name", "description"=>"Name of the error", "allowed_values"=>null, "extkey_attcode"=> 'error_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddFilterFromAttribute("infra_id"); + MetaModel::Init_AddFilterFromAttribute("error_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('infra_id', 'error_id')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('infra_id', 'infra_status','error_id')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('infra_id', 'error_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('infra_id', 'error_id')); // Criteria of the advanced search form + } + + +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Contract and a Document +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkDocumentError extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "DocumentsErrorLinks", + "description" => "A link between a document and a known error", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "link_type", + "state_attcode" => "", + "reconc_keys" => array("doc_name", "error_name"), + "db_table" => "documents_error_link", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("doc_id", array("targetclass"=>"bizDocument", "label"=>"Document Name", "description"=>"id of the Document", "allowed_values"=>null, "sql"=>"doc_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("doc_name", array("label"=>"Document", "description"=>"name of the document", "allowed_values"=>null, "extkey_attcode"=> 'doc_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("error_id", array("targetclass"=>"bizKnownError", "label"=>"Error", "description"=>"Error linked to this document", "allowed_values"=>null, "sql"=>"error_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("error_name", array("label"=>"Error name", "description"=>"name of the linked error", "allowed_values"=>null, "extkey_attcode"=> 'error_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("link_type", array("label"=>"link_type", "description"=>"Type of the link", "allowed_values"=>null, "sql"=>"link_type", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("doc_id"); + MetaModel::Init_AddFilterFromAttribute("doc_name"); + MetaModel::Init_AddFilterFromAttribute("error_id"); + MetaModel::Init_AddFilterFromAttribute("error_name"); + MetaModel::Init_AddFilterFromAttribute("link_type"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('doc_id', 'error_name', 'link_type')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('doc_id', 'error_name', 'link_type')); // Attributes to be displayed for a list + } +} + + +?> diff --git a/business/ServiceMgmt.business.php b/business/ServiceMgmt.business.php new file mode 100644 index 000000000..5304b980f --- /dev/null +++ b/business/ServiceMgmt.business.php @@ -0,0 +1,259 @@ + "bizmodel,searchable", + "name" => "Contract", + "description" => "Contract signed by an organization", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "status", + "reconc_keys" => array("customer_id", "name"), // inherited attributes + "db_table" => "contracts", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/contract.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"Name", "description"=>"Name of the contract", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("customer_id", array("targetclass"=>"bizOrganization", "label"=>"Customer", "description"=>"Customer for this contract", "allowed_values"=>null, "sql"=>"customer_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("customer_name", array("label"=>"Customer", "description"=>"name of the Customer", "allowed_values"=>null, "extkey_attcode"=> 'customer_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("provider_id", array("targetclass"=>"bizOrganization", "label"=>"Provider", "description"=>"Provider for this contract", "allowed_values"=>null, "sql"=>"provider_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("provider_name", array("label"=>"Provider", "description"=>"name of the service provider", "allowed_values"=>null, "extkey_attcode"=> 'provider_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("service_name", array("label"=>"Service Name", "description"=>"Name of service for this contract", "allowed_values"=>null, "sql"=>"service_name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("team_id", array("targetclass"=>"bizTeam", "label"=>"Team", "description"=>"Team managing this contract", "allowed_values"=>null, "sql"=>"team_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("team_name", array("label"=>"Team", "description"=>"name of the team managing this contract", "allowed_values"=>null, "extkey_attcode"=> 'team_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeEnum("service_level", array("label"=>"Service Level", "description"=>"Level of service for this contract", "allowed_values"=>new ValueSetEnum("Gold,Silver,Bronze"), "sql"=>"service_level", "default_value"=>"Bronze", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("cost_unit", array("label"=>"Cost unit", "description"=>"Cost unit to compute global cost for this contract", "allowed_values"=>new ValueSetEnum("Devices,Persons,Applications,Global"), "sql"=>"cost_unit", "default_value"=>"Global", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("cost_freq", array("label"=>"Cost frequency", "description"=>"Frequency of cost for this contract", "allowed_values"=>new ValueSetEnum("Monthly,Yearly,Once"), "sql"=>"cost_freq", "default_value"=>"Once", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("cost", array("label"=>"Cost", "description"=>"Cost of this contract", "allowed_values"=>null, "sql"=>"cost", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("currency", array("label"=>"Currency", "description"=>"Currency of cost for this contract", "allowed_values"=>new ValueSetEnum("Euros,Dollars"), "sql"=>"currency", "default_value"=>"Euros", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeText("description", array("label"=>"Description", "description"=>"Description of this contract", "allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("move2prod_date", array("label"=>"Date of move to production", "description"=>"Date when the contract is on production", "allowed_values"=>null, "sql"=>"move2prod_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("end_prod", array("label"=>"Date of end of production", "description"=>"Date when the contract is stopped", "allowed_values"=>null, "sql"=>"end_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("status", array("label"=>"Status", "description"=>"Status of the contract", "allowed_values"=>new ValueSetEnum("New, Negotiating, Signed, Production, Notice, Finished"), "sql"=>"status", "default_value"=>"New", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of the contract", "allowed_values"=>new ValueSetEnum("Hardware,Software,Support,Licence"), "sql"=>"type", "default_value"=>"Support", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeInteger("version_number", array("label"=>"Version number", "description"=>"Revision number for this contract", "allowed_values"=>null, "sql"=>"version_number", "default_value"=>1, "is_null_allowed"=>false, "depends_on"=>array()))); + + + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("service_name"); + MetaModel::Init_AddFilterFromAttribute("provider_id"); + MetaModel::Init_AddFilterFromAttribute("customer_id"); + MetaModel::Init_AddFilterFromAttribute("team_id"); + MetaModel::Init_AddFilterFromAttribute("team_name"); + MetaModel::Init_AddFilterFromAttribute("service_level"); + MetaModel::Init_AddFilterFromAttribute("end_prod"); + MetaModel::Init_AddFilterFromAttribute("status"); + MetaModel::Init_AddFilterFromAttribute("version_number"); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("type"); + + + // Life cycle + MetaModel::Init_DefineState("New", array("label"=>"New", "description"=>"Newly created contract", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Negotiating", array("label"=>"Negotiating", "description"=>"The contract is being worked on", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Signed", array("label"=>"Signed", "description"=>"The contract has been signed", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Production", array("label"=>"Production", "description"=>"The contract is effective in production", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Notice", array("label"=>"Notice", "description"=>"The contract is about to be terminated", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Finished", array("label"=>"Finished", "description"=>"The contract is terminated", "attribute_inherit"=>null, + "attribute_list"=>array())); + + MetaModel::Init_DefineStimulus("ev_freeze_version", new StimulusUserAction(array("label"=>"Freeze this version", "description"=>"This version of the contract is published"))); + MetaModel::Init_DefineStimulus("ev_sign", new StimulusUserAction(array("label"=>"Sign this contract", "description"=>"This contract is being signed"))); + MetaModel::Init_DefineStimulus("ev_begin", new StimulusUserAction(array("label"=>"Move to production", "description"=>"The contract becomes applicable in production"))); + MetaModel::Init_DefineStimulus("ev_notice", new StimulusUserAction(array("label"=>"Start notice period", "description"=>"The end date of the contract is approaching"))); + MetaModel::Init_DefineStimulus("ev_terminate", new StimulusUserAction(array("label"=>"Ends this contract", "description"=>"The contract is ending"))); + MetaModel::Init_DefineStimulus("ev_elapsed", new StimulusUserAction(array("label"=>"Times up [Do not click!]", "description"=>"The contract over"))); + + MetaModel::Init_DefineTransition("New", "ev_freeze_version", array("target_state"=>"Negotiating", "actions"=>array('IncrementVersion'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Negotiating", "ev_freeze_version", array("target_state"=>"Negotiating", "actions"=>array('IncrementVersion'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Negotiating", "ev_sign", array("target_state"=>"Signed", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Negotiating", "ev_terminate", array("target_state"=>"Finished", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Signed", "ev_freeze_version", array("target_state"=>"Signed", "actions"=>array('IncrementVersion'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Signed", "ev_begin", array("target_state"=>"Production", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Signed", "ev_terminate", array("target_state"=>"Finished", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Production", "ev_freeze_version", array("target_state"=>"Production", "actions"=>array('IncrementVersion'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Production", "ev_elapsed", array("target_state"=>"Notice", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Production", "ev_terminate", array("target_state"=>"Finished", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Notice", "ev_elapsed", array("target_state"=>"Finished", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Notice", "ev_terminate", array("target_state"=>"Finished", "actions"=>array(), "user_restriction"=>null)); + + + MetaModel::Init_SetZListItems('details', array('name', 'status', 'customer_id', 'service_name','provider_id','type','description','team_id','service_level','cost','currency','cost_unit','cost_freq','move2prod_date','end_prod', 'version_number')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'customer_id', 'provider_id','service_name','service_level','type')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status','service_name','provider_id','team_name','service_level','type')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'service_name','provider_id','team_name', 'service_level', 'org_id')); // Criteria of the advanced search form + + } + + // State machine actions + public function IncrementVersion($sStimulusCode) + { + $this->Set('version_number', $this->Get('version_number') + 1); + return true; + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Infra and a Contract +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkInfraContract extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "InfraContractLinks", + "description" => "Infra covered by a contract", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "coverage", // ???? + "state_attcode" => "", + "reconc_keys" => array("infra_id","contract_id"), // ???? + "db_table" => "infra_contract_links", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("infra_id", array("targetclass"=>"logInfra", "jointype"=> '', "label"=>"Infrastructure", "description"=>"The infrastructure impacted", "allowed_values"=>null, "sql"=>"infra_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_name", array("label"=>"Infrastructure name", "description"=>"Name of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_status", array("label"=>"Status", "description"=>"Status of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"status"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contract_id", array("targetclass"=>"bizContract", "jointype"=> '', "label"=>"Contract name", "description"=>"Contract id", "allowed_values"=>null, "sql"=>"contract_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contract_name", array("label"=>"Contract name", "description"=>"Name of the contract", "allowed_values"=>null, "extkey_attcode"=> 'contract_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("coverage", array("label"=>"coverage", "description"=>"coverage for the given infra", "allowed_values"=>null, "sql"=>"coverage", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("infra_id"); + MetaModel::Init_AddFilterFromAttribute("contract_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('infra_id', 'contract_id', 'coverage')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('infra_id', 'infra_status','contract_id' , 'coverage')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('infra_id', 'contract_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('infra_id', 'contract_id')); // Criteria of the advanced search form + } + + +} +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any contact and a Contract +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkContactContract extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "ContactContractLink", + "description" => "Contact associated to a contract", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "role", // ???? + "state_attcode" => "", + "reconc_keys" => array("role"), // ???? + "db_table" => "contact_contract", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contact_id", array("targetclass"=>"bizContact", "jointype"=> '', "label"=>"Contact", "description"=>"The contact linked to contract", "allowed_values"=>null, "sql"=>"contact_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_mail", array("label"=>"Contact E-mail", "description"=>"Mail for the contact", "allowed_values"=>null, "extkey_attcode"=> 'contact_id', "target_attcode"=>"email"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contract_id", array("targetclass"=>"bizContract", "jointype"=> '', "label"=>"Contract", "description"=>"Contract ID", "allowed_values"=>null, "sql"=>"contract_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contract_name", array("label"=>"Contract name", "description"=>"Name of the contract", "allowed_values"=>null, "extkey_attcode"=> 'contract_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("role", array("label"=>"Role", "description"=>"Role of this contact for this contract", "allowed_values"=>null, "sql"=>"role", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("contract_id"); + MetaModel::Init_AddFilterFromAttribute("contact_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('contract_id', 'contact_id', 'role')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('contract_id', 'contact_id', 'role')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('contract_id', 'contact_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('contract_id', 'contact_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('contract_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('contact_id', $oGenerator->GenerateKey("bizIncidentTicket", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('role', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } + +} +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Contract and a Document +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkDocumentContract extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "DocumentsContractLinks", + "description" => "A link between a document and another contract", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "link_type", + "state_attcode" => "", + "reconc_keys" => array("doc_name", "contract_name"), + "db_table" => "documents_contracts", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("doc_id", array("targetclass"=>"bizDocument", "label"=>"Document Name", "description"=>"id of the Document", "allowed_values"=>null, "sql"=>"doc_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("doc_name", array("label"=>"Document", "description"=>"name of the document", "allowed_values"=>null, "extkey_attcode"=> 'doc_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contract_id", array("targetclass"=>"bizContract", "label"=>"Contract", "description"=>"Contract linked to this document", "allowed_values"=>null, "sql"=>"contract_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contract_name", array("label"=>"contract name", "description"=>"name of the linked contract", "allowed_values"=>null, "extkey_attcode"=> 'contract_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("link_type", array("label"=>"link_type", "description"=>"Type of the link", "allowed_values"=>null, "sql"=>"link_type", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("doc_id"); + MetaModel::Init_AddFilterFromAttribute("doc_name"); + MetaModel::Init_AddFilterFromAttribute("contract_id"); + MetaModel::Init_AddFilterFromAttribute("contract_name"); + MetaModel::Init_AddFilterFromAttribute("link_type"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('doc_id', 'contract_name', 'link_type')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('doc_id', 'contract_name', 'link_type')); // Attributes to be displayed for a list + } +} + + +?> diff --git a/business/business_itopbegins.class.inc.php b/business/business_itopbegins.class.inc.php new file mode 100644 index 000000000..5ac001c57 --- /dev/null +++ b/business/business_itopbegins.class.inc.php @@ -0,0 +1,261 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + + +/////////////////////////////////////////////////////////////////////////////// +// Business implementation demo +/////////////////////////////////////////////////////////////////////////////// + + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbContact extends CMDBObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "klassContact", + "description" => "klass contact description", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "att_contact_name", + "state_attcode" => "", + "reconc_keys" => array("att_contact_name"), + "db_table" => "contact", + "db_key_field" => "contactid", + "db_finalclass_field" => "actualclass", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("att_contact_name", array("label"=>"name of the contact", "description"=>"blah", "allowed_values"=>null, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeInteger("att_contact_availability", array("label"=>"degree of availability in percent", "description"=>"blah", "allowed_values"=>null, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"availability"))); + MetaModel::Init_AddAttribute(new AttributeDate("start_date", array("label"=>"Starting date", "description"=>"Incident starting date", "allowed_values"=>null, "sql"=>"start_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("att_contact_name"); + MetaModel::Init_AddFilterFromAttribute("att_contact_availability"); + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbPerson extends cmdbContact +{ + public static function Init() + { + $oValsDunsNumber = new ValueSetObjects("cmdbCompany: att_company_dunsnumber Begins with '$[duns_prm::]'", "att_company_dunsnumber", array("att_company_dunsnumber"=>true)); + + $aParams = array + ( + "category" => "blah", + "name" => "klassPerson", + "description" => "klass person description", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "att_contact_name", + "state_attcode" => "", + "reconc_keys" => array("att_contact_name"), + "db_table" => "person", + "db_key_field" => "personid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("att_person_email", array("label"=>"iMaile", "description"=>"imelle", "allowed_values"=>$oValsDunsNumber, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"email"))); + MetaModel::Init_AddAttribute(new AttributeString("att_person_name", array("label"=>"secName", "description"=>"secondary name", "allowed_values"=>new ValueSetEnum(array("nom1", "nom2", "nom10", "no", "noms", "")), "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"name"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("att_person_email"); + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbSubcontractor extends cmdbPerson +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "klassSubcontractor", + "description" => "klass subcontractor description", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "att_contact_name", + "state_attcode" => "", + "reconc_keys" => array("att_contact_name"), + "db_table" => "subcontractor", + "db_key_field" => "subcontractorid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("att_contractinfo", array("label"=>"contract info", "description"=>"blah", "allowed_values"=>null, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"contractinfo"))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("ext_subcontractor_provider", array("label"=>"ssii", "description"=>"blah", "allowed_values"=>null, "sql"=>"provider", "targetclass"=>"cmdbProvider", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("extatt_subcontractor_provider_ref", array("label"=>"ref", "description"=>"blah", "allowed_values"=>null, "extkey_attcode"=>"ext_subcontractor_provider", "target_attcode"=>"att_provider_ref"))); + + MetaModel::Init_AddAttribute(new AttributeExternalKey("ext_subcontractor_tutor", array("label"=>"tutor", "description"=>"blah", "allowed_values"=>null, "sql"=>"tutor", "targetclass"=>"cmdbPerson", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("extatt_subcontractor_tutor_email", array("label"=>"tutor email", "description"=>"blah", "allowed_values"=>null, "extkey_attcode"=>"ext_subcontractor_tutor", "target_attcode"=>"att_person_email"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("extatt_subcontractor_tutor_secondname", array("label"=>"2ndname (ext field)", "description"=>"blah", "allowed_values"=>null, "extkey_attcode"=>"ext_subcontractor_tutor", "target_attcode"=>"att_person_name"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("extatt_subcontractor_tutor_secondname"); + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbCrowd extends cmdbObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "klassCrowd", + "description" => "klass crowd description", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "att_crowd_peoplecount", + "state_attcode" => "", + "reconc_keys" => array("att_crowd_peoplecount"), + "db_table" => "crowd", + "db_key_field" => "crowdid", + "db_finalclass_field" => "crowdclass", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeInteger("att_crowd_peoplecount", array("label"=>"people count", "description"=>"blah", "allowed_values"=>null, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"peoplecount"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("att_crowd_peoplecount"); + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbCompany extends cmdbCrowd +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "klassCompany", + "description" => "klass company description", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "att_company_dunsnumber", + "state_attcode" => "", + "reconc_keys" => array("att_company_dunsnumber"), + "db_table" => "company", + "db_key_field" => "companyid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("att_company_dunsnumber", array("label"=>"duns number", "description"=>"blah", "allowed_values"=>null, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"dunsnumber"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("att_company_dunsnumber"); + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbProvider extends cmdbCompany +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "klassProvider", + "description" => "klass provider description", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "att_provider_ref", + "state_attcode" => "", + "reconc_keys" => array("att_provider_ref"), + "db_table" => "provider", + "db_key_field" => "providerid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeInteger("att_provider_ref", array("label"=>"provider ref", "description"=>"blah", "allowed_values"=>null, "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array(), "sql"=>"providerref"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("att_provider_ref"); + } +} + + +?> diff --git a/business/business_test.class.inc.php b/business/business_test.class.inc.php new file mode 100644 index 000000000..6c0e0feb6 --- /dev/null +++ b/business/business_test.class.inc.php @@ -0,0 +1,372 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +/////////////////////////////////////////////////////////////////////////////// +// Business implementation demo +/////////////////////////////////////////////////////////////////////////////// + +MetaModel::RegisterRelation("Potes", array("description"=>"ceux dont l'email ressemble au mien", "verb_down"=>"est pote de", "verb_up"=>"est pote de")); + + +MetaModel::RegisterZList("list1", array("description"=>"une premiere list, just for fun", "type"=>"attributes")); +MetaModel::RegisterZList("list2", array("description"=>"la secunda e meliora", "type"=>"attributes")); +MetaModel::RegisterZList("list3", array("description"=>"la variante qui tue", "type"=>"filters")); + + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbObjectHomeMade extends cmdbObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "anyObject", + "description" => "std object", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(""), + "db_table" => "", + "db_key_field" => "", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + } + protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields) + { + $sLabel = htmlentities(implode(' / ', $aAvailableFields)); + $sHint = htmlentities("$sObjClass::$sObjKey"); + return "$sLabel"; + } + + public static function GetRelationQueries($sRelCode) + { + //trigger_error("GetRelationQueries: cmdbObjectHomeMade"); + switch ($sRelCode) + { + case "Potes": + $aRels = array("xxxx" => array("sQuery"=>"cmdbContact: pkey = 40", "bPropagate"=>true, "iDistance"=>3)); + return $aRels; + } + } +} + + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbContact extends cmdbObjectHomeMade +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Contact", + "description" => "Un object que l'on peut communiquer avec", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "name", + "state_attcode" => "etat", + "reconc_keys" => array("name"), + "db_table" => "contact", + "db_key_field" => "contactid", + "db_finalclass_field" => "actualclass", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("etat", array("label"=>"l'etat", "description"=>"les etats d'ame d'eric", "allowed_values"=>new ValueSetEnum('justborn, 15, 21'), "sql"=>"etat", "default_value"=>"justborn", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"nom", "description"=>"ze equipe", "allowed_values"=>null, "sql"=>"name", "default_value"=>"XXXX", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("email", array("label"=>"iMaile", "description"=>"imelle", "allowed_values"=>null, "sql"=>"email", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("owner", array("label"=>"owned by", "description"=>"organization owning the team", "allowed_values"=>null, "sql"=>"ownerorg", "targetclass"=>"cmdbOrga", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ownername", array("label"=>"owned by", "description"=>"name of organization owning the team", "allowed_values"=>null, "extkey_attcode"=>"owner", "target_attcode"=>"_name_"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ownertnut", array("label"=>"owntnut", "description"=>"blah tnut blah", "allowed_values"=>null, "extkey_attcode"=>"owner", "target_attcode"=>"_dunsnumber_"))); + + MetaModel::Init_AddAttribute(new AttributeLinkedSet("myworkshops", array("label"=>"held workshops", "description"=>"blah tnut blah", "depends_on"=>array(), "linked_class"=>"cmdbLiens", "ext_key_to_me"=>"tocontact", "count_min"=>1, "count_max"=>10, "allowed_values"=>null))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("owner"); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("ownername"); + + MetaModel::Init_SetZListItems("list1", array("name", "email")); + MetaModel::Init_SetZListItems("list2", array()); + MetaModel::Init_SetZListItems("list3", array("ownername")); + + MetaModel::Init_DefineState("justborn", array("label"=>"just born", "description"=>"too young to die", "attribute_inherit"=>null, "attribute_list"=>array("owner"=>OPT_ATT_MANDATORY))); + MetaModel::Init_DefineState("15", array("label"=>"student", "description"=>"stupid age", "attribute_inherit"=>"justborn", "attribute_list"=>array("owner"=>OPT_ATT_MUSTPROMPT, "email"=>OPT_ATT_MUSTPROMPT))); + MetaModel::Init_DefineState("21", array("label"=>"old", "description"=>"one foot in the grave", "attribute_inherit"=>"15", "attribute_list"=>array("email"=>OPT_ATT_READONLY|OPT_ATT_MUSTCHANGE))); + + MetaModel::Init_DefineStimulus("toschool", new StimulusUserAction(array("label"=>"go to school", "description"=>"start learning stupid things"))); + MetaModel::Init_DefineStimulus("raise", new StimulusUserAction(array("label"=>"grow!", "description"=>"eat tons of BigMACs"))); + + MetaModel::Init_DefineTransition("justborn", "toschool", array("target_state"=>"15", "actions"=>array('MyLifecycleHandler', 'MyLifecycleHandler2'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("15", "raise", array("target_state"=>"21", "actions"=>null, "user_restriction"=>null)); + } + + public static function GetRelationQueries($sRelCode) + { + //trigger_error("GetRelationQueries: cmdbContact"); + switch ($sRelCode) + { + case "Potes": + $aRels = array( + "zz1" => array("sQuery"=>"cmdbContact: name Begins with '\$[this.name::]' AND pkey != \$[this.pkey::]", "bPropagate"=>false, "iDistance"=>3), + "zz2" => array("sQuery"=>"cmdbContact: owner = \$[this.owner::] AND owner != 2", "bPropagate"=>false, "iDistance"=>3), + ); + return array_merge($aRels, parent::GetRelationQueries($sRelCode)); + } + } + + public function MyLifecycleHandler($sStimulusCode) + { + echo "

youhou!

"; + return true; + } + public function MyLifecycleHandler2($sStimulusCode) + { + echo "

... les papous...

"; + return true; + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbTeam extends cmdbContact +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Equipado", + "description" => "Un regroupement de gens", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "email", + "state_attcode" => "", + "reconc_keys" => array("email"), + "db_table" => "team", + "db_key_field" => "teamid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_OverloadAttributeParams("email", array("label"=>"email2", "description"=>"emailleu22")); + MetaModel::Init_AddAttribute(new AttributeInteger("headcount", array("label"=>"nombre", "description"=>"combien ils sont", "allowed_values"=>null, "sql"=>"headcount", "default_value"=>654321, "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("headcount"); + + MetaModel::Init_SetZListItems("noneditable", array("name")); + } + + public function ComputeValues() + { + //echo "Set(), function ComputeValues has been found for ".get_class($this)."
\n"; + $this->Set("name", $this->Get("email")." and ".$this->Get("headcount")); + } + + public static function GetRelationQueries($sRelCode) + { + //trigger_error("GetRelationQueries: cmdbTeam"); + switch ($sRelCode) + { + case "Potes": + //$aRels = array("Relies on" => array("sQuery"=>"cmdbContact: name Begins with 'Louis'", "bPropagate"=>false, "iDistance"=>3)); + return array_merge(array(), parent::GetRelationQueries($sRelCode)); + } + } +} + + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbOrga extends cmdbObjectHomeMade +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Organization", + "description" => "Une entite qui possede des choses", + "key_type" => "", + "key_label" => "", + "name_attcode" => "_name_", + "state_attcode" => "", + "reconc_keys" => array("_name_"), + "db_table" => "organization", + "db_key_field" => "orgid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("_name_", array("label"=>"namo", "description"=>"official company name", "allowed_values"=>null, "sql"=>"name", "default_value"=>"XXXX", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("_status_", array("label"=>"step", "description"=>"step or status, etc.", "allowed_values"=>null, "sql"=>"status", "default_value"=>"XXXX", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("_dunsnumber_", array("label"=>"duns debile number", "description"=>"une bonne idee a OVSD", "allowed_values"=>null, "sql"=>"dunsnumber", "default_value"=>99007, "is_null_allowed"=>false, "depends_on"=>array()))); +// not yet allowed MetaModel::Init_AddAttribute(new AttributeInteger("_dunsnumberBY2_", array("label"=>"dummy duns", "description"=>"deux fois plus debile", "allowed_values"=>null, "sql"=>"dunsnumber * 3.141592654"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("_name_"); + + MetaModel::Init_SetZListItems("list1", array("_status_")); + MetaModel::Init_SetZListItems("list2", array()); + MetaModel::Init_SetZListItems("list3", array("_name_")); + } + +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbLiens extends cmdbObjectHomeMade +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Liens_entre_contacts_et_workshop", + "description" => "Une entite qui lie des contacts et workshops", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "function", + "state_attcode" => "", + "reconc_keys" => array("function"), + "db_table" => "role_ws", + "db_key_field" => "linkid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("function", array("label"=>"fonction", "description"=>"la fonction...", "allowed_values"=>null, "sql"=>"function", "default_value"=>"XXXX", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("a1", array("label"=>"a1", "description"=>"a1", "allowed_values"=>null, "sql"=>"a1", "default_value"=>"XXXX", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("a2", array("label"=>"a1", "description"=>"a2", "allowed_values"=>null, "sql"=>"a2", "default_value"=>"XXXX", "is_null_allowed"=>true, "depends_on"=>array()))); + + // What makes it being a link... + MetaModel::Init_AddAttribute(new AttributeExternalKey("toworkshop", array("label"=>"participates in", "description"=>"workshop in wich the person is participating", "allowed_values"=>null, "sql"=>"ws_id", "targetclass"=>"cmdbWorkshop", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ws_info", array("label"=>"name", "description"=>"namedescription", "allowed_values"=>null, "extkey_attcode"=>"toworkshop", "target_attcode"=>"namitus"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("tocontact", array("label"=>"is held by", "description"=>"people involved in that mess", "allowed_values"=>null, "sql"=>"contactid", "targetclass"=>"cmdbContact", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_info", array("label"=>"name", "description"=>"namedescription", "allowed_values"=>null, "extkey_attcode"=>"tocontact", "target_attcode"=>"name"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("function"); + + MetaModel::Init_SetZListItems("list1", array("toworkshop", "contact_info")); + MetaModel::Init_SetZListItems("list2", array("function")); + MetaModel::Init_SetZListItems("list3", array("function")); + } + + public static function GetRelationQueries($sRelCode) + { + trigger_error("GetRelationQueries: cmdbLiens"); + return array("Relies on" => array("sQuery"=>"", "bPropagate"=>true, "iDistance"=>3)); + } +} + +/** + * blah blah + * + * @package iTopUnitTests + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class cmdbWorkshop extends cmdbObjectHomeMade +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Workshop", + "description" => "Une entite qui pond des theories insensees", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "namitus", + "state_attcode" => "", + "reconc_keys" => array("namitus"), + "db_table" => "workshop", + "db_key_field" => "ws_id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("namitus", array("label"=>"namo", "description"=>"nom imbitique pour pondeurs de debilites", "allowed_values"=>null, "sql"=>"name", "default_value"=>"XXXX", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("namitus"); + + MetaModel::Init_SetZListItems("list1", array("namitus")); + MetaModel::Init_SetZListItems("list2", array()); + MetaModel::Init_SetZListItems("list3", array("namitus")); + } + + public static function GetRelationQueries($sRelCode) + { + trigger_error("GetRelationQueries: cmdbWorkshop"); + return array("Relies on" => array("sQuery"=>"", "bPropagate"=>true, "iDistance"=>3)); + } +} + + +?> diff --git a/business/data.samples.inc.php b/business/data.samples.inc.php new file mode 100644 index 000000000..8f76a3bd1 --- /dev/null +++ b/business/data.samples.inc.php @@ -0,0 +1,4845 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +$aCompanies = array(); +$aCompanies[] = array('name' => "iTop", 'domain' => "itop.com", 'code' => "ITOP"); +$aCompanies[] = array('name' => "R-Skin Design", 'domain' => "rskindesign.com", 'code' => "RSKIN"); +$aCompanies[] = array('name' => "Pen Shop", 'domain' => "penshop.com", 'code' => "PENSHOP"); +$aCompanies[] = array('name' => "Joyant", 'domain' => "joyan.com", 'code' => "JOYAN"); +$aCompanies[] = array('name' => "Inhabitants", 'domain' => "inhabitants.org", 'code' => "INH"); +$aCompanies[] = array('name' => "Electric Poulp", 'domain' => "epoulp.com", 'code' => "EPOULP"); +$aCompanies[] = array('name' => "Well Steam", 'domain' => "wellsteam.com", 'code' => "WEELSTM"); +$aCompanies[] = array('name' => "Express Engine", 'domain' => "expressengine.com", 'code' => "XPRESS"); +$aCompanies[] = array('name' => "Electric Bytes", 'domain' => "ebytes.com", 'code' => "EBYTES"); +$aCompanies[] = array('name' => "Iceberg", 'domain' => "iceberg.com", 'code' => "ICEBERG"); +$aCompanies[] = array('name' => "VThird", 'domain' => "vthird.com", 'code' => "V3RD"); +$aCompanies[] = array('name' => "AAssurance", 'domain' => "aasurance.com", 'code' => "AASSUR"); +$aCompanies[] = array('name' => "Webgets", 'domain' => "webgets.com", 'code' => "WEBGETS"); +$aCompanies[] = array('name' => "Brianair", 'domain' => array("brianair.co.uk", "brianair.com", "britanair.com"), 'code' => "BRAIR"); +$aCompanies[] = array('name' => "NetCMDB", 'domain' => array("netcmdb.com", "netcmdb.net", "octopus.com"), 'code' => "NECMDB"); +$aCompanies[] = array('name' => "Zen Garden", 'domain' => "zengarden.net", 'code' => "ZEN"); +$aCompanies[] = array('name' => "T-Supply", 'domain' => "tsupply.de", 'code' => "TSUPPLY"); +$aCompanies[] = array('name' => "Berliner Druckmaschinen", 'domain' => "bdm.de", 'code' => "BDM"); +$aCompanies[] = array('name' => "ZKS", 'domain' => "zks.com", 'code' => "ZKS"); +$aCompanies[] = array('name' => "Air Amérique", 'domain' => "airamerique.fr", 'code' => "AIRAM"); +$aCompanies[] = array('name' => "Radio Mongo", 'domain' => "radio-mongo.fr", 'code' => "MONGO"); +$aCompanies[] = array('name' => "Radio Andorre", 'domain' => "radio.ad", 'code' => "RADAND"); +$aCompanies[] = array('name' => "Idahos Mutual Life Insurance", 'domain' => "idahosmutual.com", 'code' => "IMLI"); +$aCompanies[] = array('name' => "Amott Laboratories", 'domain' => "amott.com", 'code' => "AMOTT"); +$aCompanies[] = array('name' => "Hereford Financial Services Group", 'domain' => "hfsg.com", 'code' => "HFSG"); +$aCompanies[] = array('name' => "Techni Data Corp", 'domain' => array("technidata.com", "techniservices.com"), 'code' => "TECHNI"); +$aCompanies[] = array('name' => "Southwestern Mutual Life Insurance", 'domain' => array("swmutual.com", "swmutual-loans.com", "insurance.swmutual.com"), 'code' => "SWMUTUAL"); +$aCompanies[] = array('name' => "American Solar Power", 'domain' => "solarpower.com", 'code' => "ASP"); +$aCompanies[] = array('name' => "Altena", 'domain' => "altena.fr", 'code' => "ALTENA"); +$aCompanies[] = array('name' => "Groupe Commeco", 'domain' => "commeco.fr", 'code' => "COMMECO"); +$aCompanies[] = array('name' => "Virages", 'domain' => array("virages.fr", "virages.corp.net"), 'code' => "VIRAGES"); +$aCompanies[] = array('name' => "Ciments Lorrains", 'domain' => "cimlor.fr", 'code' => "CIMLOR"); +$aCompanies[] = array('name' => "Durand SA", 'domain' => "durand.fr", 'code' => "DURAND"); +$aCompanies[] = array('name' => "Transports Jeanton", 'domain' => "jeanton.fr", 'code' => "JEANTON"); +$aCompanies[] = array('name' => "Companie Générale du Bois", 'domain' => "cgb.fr", 'code' => "CGB"); +$aCompanies[] = array('name' => "Village Group", 'domain' => "village.com", 'code' => "VGP"); + +$aCompaniesCode = array(); +foreach($aCompanies as $aCompany) +{ + $aCompaniesCode[$aCompany['code']] = array('name' => $aCompany['name'], 'domain' => $aCompany['domain']); +} + +$aFirstNames = array(); +$aFirstNames[] = 'Enzo'; +$aFirstNames[] = 'Quentin'; +$aFirstNames[] = 'Mohamed'; +$aFirstNames[] = 'Lucas'; +$aFirstNames[] = 'Julien'; +$aFirstNames[] = 'Ethan'; +$aFirstNames[] = 'Nathan'; +$aFirstNames[] = 'Thomas'; +$aFirstNames[] = 'Nicolas'; +$aFirstNames[] = 'Alexandre'; +$aFirstNames[] = 'Theo'; +$aFirstNames[] = 'Yanis'; +$aFirstNames[] = 'Hugo'; +$aFirstNames[] = 'Rayan'; +$aFirstNames[] = 'Tom'; +$aFirstNames[] = 'Romain'; +$aFirstNames[] = 'Sacha'; +$aFirstNames[] = 'Xavier'; +$aFirstNames[] = 'Olivier'; +$aFirstNames[] = 'Antoine'; +$aFirstNames[] = 'Raphael'; +$aFirstNames[] = 'Louis'; +$aFirstNames[] = 'Clement'; +$aFirstNames[] = 'Maxime'; +$aFirstNames[] = 'Pierre'; +$aFirstNames[] = 'Jules'; +$aFirstNames[] = 'Mael'; +$aFirstNames[] = 'Axel'; +$aFirstNames[] = 'Guillaume'; +$aFirstNames[] = 'Benjamin'; +$aFirstNames[] = 'Gabriel'; +$aFirstNames[] = 'Maxence'; +$aFirstNames[] = 'Evan'; +$aFirstNames[] = 'Sebastien'; +$aFirstNames[] = 'Arthur'; +$aFirstNames[] = 'Noah'; +$aFirstNames[] = 'Kevin'; +$aFirstNames[] = 'Mathieu'; +$aFirstNames[] = 'Leo'; +$aFirstNames[] = 'Mathis'; +$aFirstNames[] = 'David'; +$aFirstNames[] = 'Florian'; +$aFirstNames[] = 'Paul'; +$aFirstNames[] = 'Tristan'; +$aFirstNames[] = 'Timeo'; +$aFirstNames[] = 'Simon'; +$aFirstNames[] = 'Matthieu'; +$aFirstNames[] = 'Cedric'; +$aFirstNames[] = 'Corentin'; +$aFirstNames[] = 'Vincent'; +$aFirstNames[] = 'Audrey'; +$aFirstNames[] = 'Aurelie'; +$aFirstNames[] = 'Manon'; +$aFirstNames[] = 'Jade'; +$aFirstNames[] = 'Lea'; +$aFirstNames[] = 'Chloe'; +$aFirstNames[] = 'Emma'; +$aFirstNames[] = 'Camille'; +$aFirstNames[] = 'Caroline'; +$aFirstNames[] = 'Marie'; +$aFirstNames[] = 'Sarah'; +$aFirstNames[] = 'Pauline'; +$aFirstNames[] = 'Lilou'; +$aFirstNames[] = 'Julie'; +$aFirstNames[] = 'Ines'; +$aFirstNames[] = 'Fanny'; +$aFirstNames[] = 'Melissa'; +$aFirstNames[] = 'Lola'; +$aFirstNames[] = 'Clara'; +$aFirstNames[] = 'Oceane'; +$aFirstNames[] = 'Sabrina'; +$aFirstNames[] = 'Mathilde'; +$aFirstNames[] = 'Laura'; +$aFirstNames[] = 'Ambre'; +$aFirstNames[] = 'Alexia'; +$aFirstNames[] = 'Elodie'; +$aFirstNames[] = 'Anais'; +$aFirstNames[] = 'Amandine'; +$aFirstNames[] = 'Sophie'; +$aFirstNames[] = 'Emilie'; +$aFirstNames[] = 'Celia'; +$aFirstNames[] = 'Malika'; +$aFirstNames[] = 'Margaux'; +$aFirstNames[] = 'Ursule'; +$aFirstNames[] = 'Louise'; +$aFirstNames[] = 'Ophelie'; +$aFirstNames[] = 'Charlotte'; +$aFirstNames[] = 'Gaetane'; +$aFirstNames[] = 'Abigail'; +$aFirstNames[] = 'Noemie'; +$aFirstNames[] = 'Coralie'; +$aFirstNames[] = 'Celine'; +$aFirstNames[] = 'Louna'; +$aFirstNames[] = 'Emeline'; +$aFirstNames[] = 'Lena'; +$aFirstNames[] = 'Marion'; +$aFirstNames[] = 'Solene'; +$aFirstNames[] = 'Alice'; +$aFirstNames[] = 'Lucie'; +$aFirstNames[] = 'Lisa'; +$aFirstNames[] = 'Jean'; +$aFirstNames[] = 'Philippe'; +$aFirstNames[] = 'Michel'; +$aFirstNames[] = 'Alain'; +$aFirstNames[] = 'Patrick'; +$aFirstNames[] = 'Pascal'; +$aFirstNames[] = 'Daniel'; +$aFirstNames[] = 'Christophe'; +$aFirstNames[] = 'Eric'; +$aFirstNames[] = 'Nicolas'; +$aFirstNames[] = 'Pierre'; +$aFirstNames[] = 'Christian'; +$aFirstNames[] = 'Laurent'; +$aFirstNames[] = 'Stephane'; +$aFirstNames[] = 'David'; +$aFirstNames[] = 'Olivier'; +$aFirstNames[] = 'Sebastien'; +$aFirstNames[] = 'Gerard'; +$aFirstNames[] = 'Frederic'; +$aFirstNames[] = 'Bernard'; +$aFirstNames[] = 'Julien'; +$aFirstNames[] = 'Dominique'; +$aFirstNames[] = 'Thierry'; +$aFirstNames[] = 'Claude'; +$aFirstNames[] = 'Francis'; +$aFirstNames[] = 'Alexandre'; +$aFirstNames[] = 'Denis'; +$aFirstNames[] = 'Francois'; +$aFirstNames[] = 'Didier'; +$aFirstNames[] = 'Vincent'; +$aFirstNames[] = 'Bruno'; +$aFirstNames[] = 'Thomas'; +$aFirstNames[] = 'Gilles'; +$aFirstNames[] = 'Jacques'; +$aFirstNames[] = 'Jerome'; +$aFirstNames[] = 'Herve'; +$aFirstNames[] = 'Marc'; +$aFirstNames[] = 'Fabrice'; +$aFirstNames[] = 'Patrice'; +$aFirstNames[] = 'Maxime'; +$aFirstNames[] = 'Anthony'; +$aFirstNames[] = 'Serge'; +$aFirstNames[] = 'Andre'; +$aFirstNames[] = 'Cedric'; +$aFirstNames[] = 'Romain'; +$aFirstNames[] = 'Guillaume'; +$aFirstNames[] = 'Arnaud'; +$aFirstNames[] = 'Franck'; +$aFirstNames[] = 'Kevin'; +$aFirstNames[] = 'Sylvain'; +$aFirstNames[] = 'Lea'; +$aFirstNames[] = 'Manon'; +$aFirstNames[] = 'Camille'; +$aFirstNames[] = 'Emma'; +$aFirstNames[] = 'Clara'; +$aFirstNames[] = 'Chloe'; +$aFirstNames[] = 'Oceane'; +$aFirstNames[] = 'Lisa'; +$aFirstNames[] = 'Laura'; +$aFirstNames[] = 'Lucie'; +$aFirstNames[] = 'Mathilde'; +$aFirstNames[] = 'Lola'; +$aFirstNames[] = 'Marie'; +$aFirstNames[] = 'Sarah'; +$aFirstNames[] = 'Celia'; +$aFirstNames[] = 'Eva'; +$aFirstNames[] = 'Julie'; +$aFirstNames[] = 'Justine'; +$aFirstNames[] = 'Emilie'; +$aFirstNames[] = 'Ines'; +$aFirstNames[] = 'Pauline'; +$aFirstNames[] = 'Anais'; +$aFirstNames[] = 'Maeva'; +$aFirstNames[] = 'Zoe'; +$aFirstNames[] = 'Juliette'; +$aFirstNames[] = 'Alice'; +$aFirstNames[] = 'Margaux'; +$aFirstNames[] = 'Louise'; +$aFirstNames[] = 'Morgane'; +$aFirstNames[] = 'Clemence'; +$aFirstNames[] = 'Lena'; +$aFirstNames[] = 'Jeanne'; +$aFirstNames[] = 'Melissa'; +$aFirstNames[] = 'Noemie'; +$aFirstNames[] = 'Charlotte'; +$aFirstNames[] = 'Elise'; +$aFirstNames[] = 'Elisa'; +$aFirstNames[] = 'Jade'; +$aFirstNames[] = 'Margot'; +$aFirstNames[] = 'Romane'; +$aFirstNames[] = 'Alexia'; +$aFirstNames[] = 'Carla'; +$aFirstNames[] = 'Alicia'; +$aFirstNames[] = 'Flavie'; +$aFirstNames[] = 'Marine'; +$aFirstNames[] = 'Lou'; +$aFirstNames[] = 'Marion'; +$aFirstNames[] = 'Claire'; +$aFirstNames[] = 'Solene'; +$aFirstNames[] = 'Amelie'; +$aFirstNames[] = 'Mary'; +$aFirstNames[] = 'Patricia'; +$aFirstNames[] = 'Linda'; +$aFirstNames[] = 'Barbara'; +$aFirstNames[] = 'Elizabeth'; +$aFirstNames[] = 'Jennifer'; +$aFirstNames[] = 'Maria'; +$aFirstNames[] = 'Susan'; +$aFirstNames[] = 'Margaret'; +$aFirstNames[] = 'Dorothy'; +$aFirstNames[] = 'Lisa'; +$aFirstNames[] = 'Nancy'; +$aFirstNames[] = 'Karen'; +$aFirstNames[] = 'Betty'; +$aFirstNames[] = 'Helen'; +$aFirstNames[] = 'Sandra'; +$aFirstNames[] = 'Donna'; +$aFirstNames[] = 'Carol'; +$aFirstNames[] = 'Ruth'; +$aFirstNames[] = 'Sharon'; +$aFirstNames[] = 'Michelle'; +$aFirstNames[] = 'Laura'; +$aFirstNames[] = 'Sarah'; +$aFirstNames[] = 'Kimberly'; +$aFirstNames[] = 'Deborah'; +$aFirstNames[] = 'Jessica'; +$aFirstNames[] = 'Shirley'; +$aFirstNames[] = 'Cynthia'; +$aFirstNames[] = 'Angela'; +$aFirstNames[] = 'Melissa'; +$aFirstNames[] = 'Brenda'; +$aFirstNames[] = 'Amy'; +$aFirstNames[] = 'Anna'; +$aFirstNames[] = 'Rebecca'; +$aFirstNames[] = 'Virginia'; +$aFirstNames[] = 'Kathleen'; +$aFirstNames[] = 'Pamela'; +$aFirstNames[] = 'Martha'; +$aFirstNames[] = 'Debra'; +$aFirstNames[] = 'Amanda'; +$aFirstNames[] = 'Stephanie'; +$aFirstNames[] = 'Carolyn'; +$aFirstNames[] = 'Christine'; +$aFirstNames[] = 'Marie'; +$aFirstNames[] = 'Janet'; +$aFirstNames[] = 'Catherine'; +$aFirstNames[] = 'Frances'; +$aFirstNames[] = 'Ann'; +$aFirstNames[] = 'Joyce'; +$aFirstNames[] = 'Diane'; +$aFirstNames[] = 'Alice'; +$aFirstNames[] = 'Julie'; +$aFirstNames[] = 'Heather'; +$aFirstNames[] = 'Teresa'; +$aFirstNames[] = 'Doris'; +$aFirstNames[] = 'Gloria'; +$aFirstNames[] = 'Evelyn'; +$aFirstNames[] = 'Jean'; +$aFirstNames[] = 'Cheryl'; +$aFirstNames[] = 'Mildred'; +$aFirstNames[] = 'Katherine'; +$aFirstNames[] = 'Joan'; +$aFirstNames[] = 'Ashley'; +$aFirstNames[] = 'Judith'; +$aFirstNames[] = 'Rose'; +$aFirstNames[] = 'Janice'; +$aFirstNames[] = 'Kelly'; +$aFirstNames[] = 'Nicole'; +$aFirstNames[] = 'Judy'; +$aFirstNames[] = 'Christina'; +$aFirstNames[] = 'Kathy'; +$aFirstNames[] = 'Theresa'; +$aFirstNames[] = 'Beverly'; +$aFirstNames[] = 'Denise'; +$aFirstNames[] = 'Tammy'; +$aFirstNames[] = 'Irene'; +$aFirstNames[] = 'Jane'; +$aFirstNames[] = 'Lori'; +$aFirstNames[] = 'Rachel'; +$aFirstNames[] = 'Marilyn'; +$aFirstNames[] = 'Andrea'; +$aFirstNames[] = 'Kathryn'; +$aFirstNames[] = 'Louise'; +$aFirstNames[] = 'Sara'; +$aFirstNames[] = 'Anne'; +$aFirstNames[] = 'Jacqueline'; +$aFirstNames[] = 'Wanda'; +$aFirstNames[] = 'Bonnie'; +$aFirstNames[] = 'Julia'; +$aFirstNames[] = 'Ruby'; +$aFirstNames[] = 'Lois'; +$aFirstNames[] = 'Tina'; +$aFirstNames[] = 'Phyllis'; +$aFirstNames[] = 'Norma'; +$aFirstNames[] = 'Paula'; +$aFirstNames[] = 'Diana'; +$aFirstNames[] = 'Annie'; +$aFirstNames[] = 'Lillian'; +$aFirstNames[] = 'Emily'; +$aFirstNames[] = 'Robin'; +$aFirstNames[] = 'Peggy'; +$aFirstNames[] = 'Crystal'; +$aFirstNames[] = 'Gladys'; +$aFirstNames[] = 'Rita'; +$aFirstNames[] = 'Dawn'; +$aFirstNames[] = 'Connie'; +$aFirstNames[] = 'Florence'; +$aFirstNames[] = 'Tracy'; +$aFirstNames[] = 'Edna'; +$aFirstNames[] = 'Tiffany'; +$aFirstNames[] = 'Carmen'; +$aFirstNames[] = 'Rosa'; +$aFirstNames[] = 'Cindy'; +$aFirstNames[] = 'Grace'; +$aFirstNames[] = 'Wendy'; +$aFirstNames[] = 'Victoria'; +$aFirstNames[] = 'Edith'; +$aFirstNames[] = 'Kim'; +$aFirstNames[] = 'Sherry'; +$aFirstNames[] = 'Sylvia'; +$aFirstNames[] = 'Josephine'; +$aFirstNames[] = 'Thelma'; +$aFirstNames[] = 'Shannon'; +$aFirstNames[] = 'Sheila'; +$aFirstNames[] = 'Ethel'; +$aFirstNames[] = 'Ellen'; +$aFirstNames[] = 'Elaine'; +$aFirstNames[] = 'Marjorie'; +$aFirstNames[] = 'Carrie'; +$aFirstNames[] = 'Charlotte'; +$aFirstNames[] = 'Monica'; +$aFirstNames[] = 'Esther'; +$aFirstNames[] = 'Pauline'; +$aFirstNames[] = 'Emma'; +$aFirstNames[] = 'Juanita'; +$aFirstNames[] = 'Anita'; +$aFirstNames[] = 'Rhonda'; +$aFirstNames[] = 'Hazel'; +$aFirstNames[] = 'Amber'; +$aFirstNames[] = 'Eva'; +$aFirstNames[] = 'Debbie'; +$aFirstNames[] = 'April'; +$aFirstNames[] = 'Leslie'; +$aFirstNames[] = 'Clara'; +$aFirstNames[] = 'Lucille'; +$aFirstNames[] = 'Jamie'; +$aFirstNames[] = 'Joanne'; +$aFirstNames[] = 'Eleanor'; +$aFirstNames[] = 'Valerie'; +$aFirstNames[] = 'Danielle'; +$aFirstNames[] = 'Megan'; +$aFirstNames[] = 'Alicia'; +$aFirstNames[] = 'Suzanne'; +$aFirstNames[] = 'Michele'; +$aFirstNames[] = 'Gail'; +$aFirstNames[] = 'Bertha'; +$aFirstNames[] = 'Darlene'; +$aFirstNames[] = 'Veronica'; +$aFirstNames[] = 'Jill'; +$aFirstNames[] = 'Erin'; +$aFirstNames[] = 'Geraldine'; +$aFirstNames[] = 'Lauren'; +$aFirstNames[] = 'Cathy'; +$aFirstNames[] = 'Joann'; +$aFirstNames[] = 'Lorraine'; +$aFirstNames[] = 'Lynn'; +$aFirstNames[] = 'Sally'; +$aFirstNames[] = 'Regina'; +$aFirstNames[] = 'Erica'; +$aFirstNames[] = 'Beatrice'; +$aFirstNames[] = 'Dolores'; +$aFirstNames[] = 'Bernice'; +$aFirstNames[] = 'Audrey'; +$aFirstNames[] = 'Yvonne'; +$aFirstNames[] = 'Annette'; +$aFirstNames[] = 'June'; +$aFirstNames[] = 'Samantha'; +$aFirstNames[] = 'Marion'; +$aFirstNames[] = 'Dana'; +$aFirstNames[] = 'Stacy'; +$aFirstNames[] = 'Ana'; +$aFirstNames[] = 'Renee'; +$aFirstNames[] = 'Ida'; +$aFirstNames[] = 'Vivian'; +$aFirstNames[] = 'Roberta'; +$aFirstNames[] = 'Holly'; +$aFirstNames[] = 'Brittany'; +$aFirstNames[] = 'Melanie'; +$aFirstNames[] = 'Loretta'; +$aFirstNames[] = 'Yolanda'; +$aFirstNames[] = 'Jeanette'; +$aFirstNames[] = 'Laurie'; +$aFirstNames[] = 'Katie'; +$aFirstNames[] = 'Kristen'; +$aFirstNames[] = 'Vanessa'; +$aFirstNames[] = 'Alma'; +$aFirstNames[] = 'Sue'; +$aFirstNames[] = 'Elsie'; +$aFirstNames[] = 'Beth'; +$aFirstNames[] = 'Jeanne'; +$aFirstNames[] = 'Vicki'; +$aFirstNames[] = 'Carla'; +$aFirstNames[] = 'Tara'; +$aFirstNames[] = 'Rosemary'; +$aFirstNames[] = 'Eileen'; +$aFirstNames[] = 'Terri'; +$aFirstNames[] = 'Gertrude'; +$aFirstNames[] = 'Lucy'; +$aFirstNames[] = 'Tonya'; +$aFirstNames[] = 'Ella'; +$aFirstNames[] = 'Stacey'; +$aFirstNames[] = 'Wilma'; +$aFirstNames[] = 'Gina'; +$aFirstNames[] = 'Kristin'; +$aFirstNames[] = 'Jessie'; +$aFirstNames[] = 'Natalie'; +$aFirstNames[] = 'Agnes'; +$aFirstNames[] = 'Vera'; +$aFirstNames[] = 'Willie'; +$aFirstNames[] = 'Charlene'; +$aFirstNames[] = 'Bessie'; +$aFirstNames[] = 'Delores'; +$aFirstNames[] = 'Melinda'; +$aFirstNames[] = 'Pearl'; +$aFirstNames[] = 'Arlene'; +$aFirstNames[] = 'Maureen'; +$aFirstNames[] = 'Colleen'; +$aFirstNames[] = 'Allison'; +$aFirstNames[] = 'Tamara'; +$aFirstNames[] = 'Joy'; +$aFirstNames[] = 'Georgia'; +$aFirstNames[] = 'Constance'; +$aFirstNames[] = 'Lillie'; +$aFirstNames[] = 'Claudia'; +$aFirstNames[] = 'Jackie'; +$aFirstNames[] = 'Marcia'; +$aFirstNames[] = 'Tanya'; +$aFirstNames[] = 'Nellie'; +$aFirstNames[] = 'Minnie'; +$aFirstNames[] = 'Marlene'; +$aFirstNames[] = 'Heidi'; +$aFirstNames[] = 'Glenda'; +$aFirstNames[] = 'Lydia'; +$aFirstNames[] = 'Viola'; +$aFirstNames[] = 'Courtney'; +$aFirstNames[] = 'Marian'; +$aFirstNames[] = 'Stella'; +$aFirstNames[] = 'Caroline'; +$aFirstNames[] = 'Dora'; +$aFirstNames[] = 'Jo'; +$aFirstNames[] = 'Vickie'; +$aFirstNames[] = 'Mattie'; +$aFirstNames[] = 'Terry'; +$aFirstNames[] = 'Maxine'; +$aFirstNames[] = 'Irma'; +$aFirstNames[] = 'Mabel'; +$aFirstNames[] = 'Marsha'; +$aFirstNames[] = 'Myrtle'; +$aFirstNames[] = 'Lena'; +$aFirstNames[] = 'Christy'; +$aFirstNames[] = 'Deanna'; +$aFirstNames[] = 'Patsy'; +$aFirstNames[] = 'Hilda'; +$aFirstNames[] = 'Gwendolyn'; +$aFirstNames[] = 'Jennie'; +$aFirstNames[] = 'Nora'; +$aFirstNames[] = 'Margie'; +$aFirstNames[] = 'Nina'; +$aFirstNames[] = 'Cassandra'; +$aFirstNames[] = 'Leah'; +$aFirstNames[] = 'Penny'; +$aFirstNames[] = 'Kay'; +$aFirstNames[] = 'Priscilla'; +$aFirstNames[] = 'Naomi'; +$aFirstNames[] = 'Carole'; +$aFirstNames[] = 'Brandy'; +$aFirstNames[] = 'Olga'; +$aFirstNames[] = 'Billie'; +$aFirstNames[] = 'Dianne'; +$aFirstNames[] = 'Tracey'; +$aFirstNames[] = 'Leona'; +$aFirstNames[] = 'Jenny'; +$aFirstNames[] = 'Felicia'; +$aFirstNames[] = 'Sonia'; +$aFirstNames[] = 'Miriam'; +$aFirstNames[] = 'Velma'; +$aFirstNames[] = 'Becky'; +$aFirstNames[] = 'Bobbie'; +$aFirstNames[] = 'Violet'; +$aFirstNames[] = 'Kristina'; +$aFirstNames[] = 'Toni'; +$aFirstNames[] = 'Misty'; +$aFirstNames[] = 'Mae'; +$aFirstNames[] = 'Shelly'; +$aFirstNames[] = 'Daisy'; +$aFirstNames[] = 'Ramona'; +$aFirstNames[] = 'Sherri'; +$aFirstNames[] = 'Erika'; +$aFirstNames[] = 'Katrina'; +$aFirstNames[] = 'Claire'; +$aFirstNames[] = 'Lindsey'; +$aFirstNames[] = 'Lindsay'; +$aFirstNames[] = 'Geneva'; +$aFirstNames[] = 'Guadalupe'; +$aFirstNames[] = 'Belinda'; +$aFirstNames[] = 'Margarita'; +$aFirstNames[] = 'Sheryl'; +$aFirstNames[] = 'Cora'; +$aFirstNames[] = 'Faye'; +$aFirstNames[] = 'Ada'; +$aFirstNames[] = 'Natasha'; +$aFirstNames[] = 'Sabrina'; +$aFirstNames[] = 'Isabel'; +$aFirstNames[] = 'Marguerite'; +$aFirstNames[] = 'Hattie'; +$aFirstNames[] = 'Harriet'; +$aFirstNames[] = 'Molly'; +$aFirstNames[] = 'Cecilia'; +$aFirstNames[] = 'Kristi'; +$aFirstNames[] = 'Brandi'; +$aFirstNames[] = 'Blanche'; +$aFirstNames[] = 'Sandy'; +$aFirstNames[] = 'Rosie'; +$aFirstNames[] = 'Joanna'; +$aFirstNames[] = 'Iris'; +$aFirstNames[] = 'Eunice'; +$aFirstNames[] = 'Angie'; +$aFirstNames[] = 'Inez'; +$aFirstNames[] = 'Lynda'; +$aFirstNames[] = 'Madeline'; +$aFirstNames[] = 'Amelia'; +$aFirstNames[] = 'Alberta'; +$aFirstNames[] = 'Genevieve'; +$aFirstNames[] = 'Monique'; +$aFirstNames[] = 'Jodi'; +$aFirstNames[] = 'Janie'; +$aFirstNames[] = 'Maggie'; +$aFirstNames[] = 'Kayla'; +$aFirstNames[] = 'Sonya'; +$aFirstNames[] = 'Jan'; +$aFirstNames[] = 'Lee'; +$aFirstNames[] = 'Kristine'; +$aFirstNames[] = 'Candace'; +$aFirstNames[] = 'Fannie'; +$aFirstNames[] = 'Maryann'; +$aFirstNames[] = 'Opal'; +$aFirstNames[] = 'Alison'; +$aFirstNames[] = 'Yvette'; +$aFirstNames[] = 'Melody'; +$aFirstNames[] = 'Luz'; +$aFirstNames[] = 'Susie'; +$aFirstNames[] = 'Olivia'; +$aFirstNames[] = 'Flora'; +$aFirstNames[] = 'Shelley'; +$aFirstNames[] = 'Kristy'; +$aFirstNames[] = 'Mamie'; +$aFirstNames[] = 'Lula'; +$aFirstNames[] = 'Lola'; +$aFirstNames[] = 'Verna'; +$aFirstNames[] = 'Beulah'; +$aFirstNames[] = 'Antoinette'; +$aFirstNames[] = 'Candice'; +$aFirstNames[] = 'Juana'; +$aFirstNames[] = 'Jeannette'; +$aFirstNames[] = 'Pam'; +$aFirstNames[] = 'Kelli'; +$aFirstNames[] = 'Hannah'; +$aFirstNames[] = 'Whitney'; +$aFirstNames[] = 'Bridget'; +$aFirstNames[] = 'Karla'; +$aFirstNames[] = 'Celia'; +$aFirstNames[] = 'Latoya'; +$aFirstNames[] = 'Patty'; +$aFirstNames[] = 'Shelia'; +$aFirstNames[] = 'Gayle'; +$aFirstNames[] = 'Della'; +$aFirstNames[] = 'Vicky'; +$aFirstNames[] = 'Lynne'; +$aFirstNames[] = 'Sheri'; +$aFirstNames[] = 'Marianne'; +$aFirstNames[] = 'Kara'; +$aFirstNames[] = 'Jacquelyn'; +$aFirstNames[] = 'Erma'; +$aFirstNames[] = 'Blanca'; +$aFirstNames[] = 'Myra'; +$aFirstNames[] = 'Leticia'; +$aFirstNames[] = 'Pat'; +$aFirstNames[] = 'Krista'; +$aFirstNames[] = 'Roxanne'; +$aFirstNames[] = 'Angelica'; +$aFirstNames[] = 'Johnnie'; +$aFirstNames[] = 'Robyn'; +$aFirstNames[] = 'Francis'; +$aFirstNames[] = 'Adrienne'; +$aFirstNames[] = 'Rosalie'; +$aFirstNames[] = 'Alexandra'; +$aFirstNames[] = 'Brooke'; +$aFirstNames[] = 'Bethany'; +$aFirstNames[] = 'Sadie'; +$aFirstNames[] = 'Bernadette'; +$aFirstNames[] = 'Traci'; +$aFirstNames[] = 'Jody'; +$aFirstNames[] = 'Kendra'; +$aFirstNames[] = 'Jasmine'; +$aFirstNames[] = 'Nichole'; +$aFirstNames[] = 'Rachael'; +$aFirstNames[] = 'Chelsea'; +$aFirstNames[] = 'Mable'; +$aFirstNames[] = 'Ernestine'; +$aFirstNames[] = 'Muriel'; +$aFirstNames[] = 'Marcella'; +$aFirstNames[] = 'Elena'; +$aFirstNames[] = 'Krystal'; +$aFirstNames[] = 'Angelina'; +$aFirstNames[] = 'Nadine'; +$aFirstNames[] = 'Kari'; +$aFirstNames[] = 'Estelle'; +$aFirstNames[] = 'Dianna'; +$aFirstNames[] = 'Paulette'; +$aFirstNames[] = 'Lora'; +$aFirstNames[] = 'Mona'; +$aFirstNames[] = 'Doreen'; +$aFirstNames[] = 'Rosemarie'; +$aFirstNames[] = 'Angel'; +$aFirstNames[] = 'Desiree'; +$aFirstNames[] = 'Antonia'; +$aFirstNames[] = 'Hope'; +$aFirstNames[] = 'Ginger'; +$aFirstNames[] = 'Janis'; +$aFirstNames[] = 'Betsy'; +$aFirstNames[] = 'Christie'; +$aFirstNames[] = 'Freda'; +$aFirstNames[] = 'Mercedes'; +$aFirstNames[] = 'Meredith'; +$aFirstNames[] = 'Lynette'; +$aFirstNames[] = 'Teri'; +$aFirstNames[] = 'Cristina'; +$aFirstNames[] = 'Eula'; +$aFirstNames[] = 'Leigh'; +$aFirstNames[] = 'Meghan'; +$aFirstNames[] = 'Sophia'; +$aFirstNames[] = 'Eloise'; +$aFirstNames[] = 'Rochelle'; +$aFirstNames[] = 'Gretchen'; +$aFirstNames[] = 'Cecelia'; +$aFirstNames[] = 'Raquel'; +$aFirstNames[] = 'Henrietta'; +$aFirstNames[] = 'Alyssa'; +$aFirstNames[] = 'Jana'; +$aFirstNames[] = 'Kelley'; +$aFirstNames[] = 'Gwen'; +$aFirstNames[] = 'Kerry'; +$aFirstNames[] = 'Jenna'; +$aFirstNames[] = 'Tricia'; +$aFirstNames[] = 'Laverne'; +$aFirstNames[] = 'Olive'; +$aFirstNames[] = 'Alexis'; +$aFirstNames[] = 'Tasha'; +$aFirstNames[] = 'Silvia'; +$aFirstNames[] = 'Elvira'; +$aFirstNames[] = 'Casey'; +$aFirstNames[] = 'Delia'; +$aFirstNames[] = 'Sophie'; +$aFirstNames[] = 'Kate'; +$aFirstNames[] = 'Patti'; +$aFirstNames[] = 'Lorena'; +$aFirstNames[] = 'Kellie'; +$aFirstNames[] = 'Sonja'; +$aFirstNames[] = 'Lila'; +$aFirstNames[] = 'Lana'; +$aFirstNames[] = 'Darla'; +$aFirstNames[] = 'May'; +$aFirstNames[] = 'Mindy'; +$aFirstNames[] = 'Essie'; +$aFirstNames[] = 'Mandy'; +$aFirstNames[] = 'Lorene'; +$aFirstNames[] = 'Elsa'; +$aFirstNames[] = 'Josefina'; +$aFirstNames[] = 'Jeannie'; +$aFirstNames[] = 'Miranda'; +$aFirstNames[] = 'Dixie'; +$aFirstNames[] = 'Lucia'; +$aFirstNames[] = 'Marta'; +$aFirstNames[] = 'Faith'; +$aFirstNames[] = 'Lela'; +$aFirstNames[] = 'Johanna'; +$aFirstNames[] = 'Shari'; +$aFirstNames[] = 'Camille'; +$aFirstNames[] = 'Tami'; +$aFirstNames[] = 'Shawna'; +$aFirstNames[] = 'Elisa'; +$aFirstNames[] = 'Ebony'; +$aFirstNames[] = 'Melba'; +$aFirstNames[] = 'Ora'; +$aFirstNames[] = 'Nettie'; +$aFirstNames[] = 'Tabitha'; +$aFirstNames[] = 'Ollie'; +$aFirstNames[] = 'Jaime'; +$aFirstNames[] = 'Winifred'; +$aFirstNames[] = 'Kristie'; +$aFirstNames[] = 'Marina'; +$aFirstNames[] = 'Alisha'; +$aFirstNames[] = 'Aimee'; +$aFirstNames[] = 'Rena'; +$aFirstNames[] = 'Myrna'; +$aFirstNames[] = 'Marla'; +$aFirstNames[] = 'Tammie'; +$aFirstNames[] = 'Latasha'; +$aFirstNames[] = 'Bonita'; +$aFirstNames[] = 'Patrice'; +$aFirstNames[] = 'Ronda'; +$aFirstNames[] = 'Sherrie'; +$aFirstNames[] = 'Addie'; +$aFirstNames[] = 'Francine'; +$aFirstNames[] = 'Deloris'; +$aFirstNames[] = 'Stacie'; +$aFirstNames[] = 'Adriana'; +$aFirstNames[] = 'Cheri'; +$aFirstNames[] = 'Shelby'; +$aFirstNames[] = 'Abigail'; +$aFirstNames[] = 'Celeste'; +$aFirstNames[] = 'Jewel'; +$aFirstNames[] = 'Cara'; +$aFirstNames[] = 'Adele'; +$aFirstNames[] = 'Rebekah'; +$aFirstNames[] = 'Lucinda'; +$aFirstNames[] = 'Dorthy'; +$aFirstNames[] = 'Chris'; +$aFirstNames[] = 'Effie'; +$aFirstNames[] = 'Trina'; +$aFirstNames[] = 'Reba'; +$aFirstNames[] = 'Shawn'; +$aFirstNames[] = 'Sallie'; +$aFirstNames[] = 'Aurora'; +$aFirstNames[] = 'Lenora'; +$aFirstNames[] = 'Etta'; +$aFirstNames[] = 'Lottie'; +$aFirstNames[] = 'Kerri'; +$aFirstNames[] = 'Trisha'; +$aFirstNames[] = 'Nikki'; +$aFirstNames[] = 'Estella'; +$aFirstNames[] = 'Francisca'; +$aFirstNames[] = 'Josie'; +$aFirstNames[] = 'Tracie'; +$aFirstNames[] = 'Marissa'; +$aFirstNames[] = 'Karin'; +$aFirstNames[] = 'Brittney'; +$aFirstNames[] = 'Janelle'; + +$aFirstNames[] = 'Lourdes'; +$aFirstNames[] = 'Laurel'; +$aFirstNames[] = 'Helene'; +$aFirstNames[] = 'Fern'; +$aFirstNames[] = 'Elva'; +$aFirstNames[] = 'Corinne'; +$aFirstNames[] = 'Kelsey'; +$aFirstNames[] = 'Ina'; +$aFirstNames[] = 'Bettie'; +$aFirstNames[] = 'Elisabeth'; +$aFirstNames[] = 'Aida'; +$aFirstNames[] = 'Caitlin'; +$aFirstNames[] = 'Ingrid'; +$aFirstNames[] = 'Iva'; +$aFirstNames[] = 'Eugenia'; +$aFirstNames[] = 'Christa'; +$aFirstNames[] = 'Goldie'; +$aFirstNames[] = 'Cassie'; +$aFirstNames[] = 'Maude'; +$aFirstNames[] = 'Jenifer'; +$aFirstNames[] = 'Therese'; +$aFirstNames[] = 'Frankie'; +$aFirstNames[] = 'Dena'; +$aFirstNames[] = 'Lorna'; +$aFirstNames[] = 'Janette'; +$aFirstNames[] = 'Latonya'; +$aFirstNames[] = 'Candy'; +$aFirstNames[] = 'Morgan'; +$aFirstNames[] = 'Consuelo'; +$aFirstNames[] = 'Tamika'; +$aFirstNames[] = 'Rosetta'; +$aFirstNames[] = 'Debora'; +$aFirstNames[] = 'Cherie'; +$aFirstNames[] = 'Polly'; +$aFirstNames[] = 'Dina'; +$aFirstNames[] = 'Jewell'; +$aFirstNames[] = 'Fay'; +$aFirstNames[] = 'Jillian'; +$aFirstNames[] = 'Dorothea'; +$aFirstNames[] = 'Nell'; +$aFirstNames[] = 'Trudy'; +$aFirstNames[] = 'Esperanza'; +$aFirstNames[] = 'Patrica'; +$aFirstNames[] = 'Kimberley'; +$aFirstNames[] = 'Shanna'; +$aFirstNames[] = 'Helena'; +$aFirstNames[] = 'Carolina'; +$aFirstNames[] = 'Cleo'; +$aFirstNames[] = 'Stefanie'; +$aFirstNames[] = 'Rosario'; +$aFirstNames[] = 'Ola'; +$aFirstNames[] = 'Janine'; +$aFirstNames[] = 'Mollie'; +$aFirstNames[] = 'Lupe'; +$aFirstNames[] = 'Alisa'; +$aFirstNames[] = 'Lou'; +$aFirstNames[] = 'Maribel'; +$aFirstNames[] = 'Susanne'; +$aFirstNames[] = 'Bette'; +$aFirstNames[] = 'Susana'; +$aFirstNames[] = 'Elise'; +$aFirstNames[] = 'Cecile'; +$aFirstNames[] = 'Isabelle'; +$aFirstNames[] = 'Lesley'; +$aFirstNames[] = 'Jocelyn'; +$aFirstNames[] = 'Paige'; +$aFirstNames[] = 'Joni'; +$aFirstNames[] = 'Rachelle'; +$aFirstNames[] = 'Leola'; +$aFirstNames[] = 'Daphne'; +$aFirstNames[] = 'Alta'; +$aFirstNames[] = 'Ester'; +$aFirstNames[] = 'Petra'; +$aFirstNames[] = 'Graciela'; +$aFirstNames[] = 'Imogene'; +$aFirstNames[] = 'Jolene'; +$aFirstNames[] = 'Keisha'; +$aFirstNames[] = 'Lacey'; +$aFirstNames[] = 'Glenna'; +$aFirstNames[] = 'Gabriela'; +$aFirstNames[] = 'Keri'; +$aFirstNames[] = 'Ursula'; +$aFirstNames[] = 'Lizzie'; +$aFirstNames[] = 'Kirsten'; +$aFirstNames[] = 'Shana'; +$aFirstNames[] = 'Adeline'; +$aFirstNames[] = 'Mayra'; +$aFirstNames[] = 'Jayne'; +$aFirstNames[] = 'Jaclyn'; +$aFirstNames[] = 'Gracie'; +$aFirstNames[] = 'Sondra'; +$aFirstNames[] = 'Carmela'; +$aFirstNames[] = 'Marisa'; +$aFirstNames[] = 'Rosalind'; +$aFirstNames[] = 'Charity'; +$aFirstNames[] = 'Tonia'; +$aFirstNames[] = 'Beatriz'; +$aFirstNames[] = 'Marisol'; +$aFirstNames[] = 'Clarice'; +$aFirstNames[] = 'Jeanine'; +$aFirstNames[] = 'Sheena'; +$aFirstNames[] = 'Angeline'; +$aFirstNames[] = 'Frieda'; +$aFirstNames[] = 'Lily'; +$aFirstNames[] = 'Robbie'; +$aFirstNames[] = 'Shauna'; +$aFirstNames[] = 'Millie'; +$aFirstNames[] = 'Claudette'; +$aFirstNames[] = 'Cathleen'; +$aFirstNames[] = 'Angelia'; +$aFirstNames[] = 'Gabrielle'; +$aFirstNames[] = 'Autumn'; +$aFirstNames[] = 'Katharine'; +$aFirstNames[] = 'Summer'; +$aFirstNames[] = 'Jodie'; +$aFirstNames[] = 'Staci'; +$aFirstNames[] = 'Lea'; +$aFirstNames[] = 'Christi'; +$aFirstNames[] = 'Jimmie'; +$aFirstNames[] = 'Justine'; +$aFirstNames[] = 'Elma'; +$aFirstNames[] = 'Luella'; +$aFirstNames[] = 'Margret'; +$aFirstNames[] = 'Dominique'; +$aFirstNames[] = 'Socorro'; +$aFirstNames[] = 'Rene'; +$aFirstNames[] = 'Martina'; +$aFirstNames[] = 'Margo'; +$aFirstNames[] = 'Mavis'; +$aFirstNames[] = 'Callie'; +$aFirstNames[] = 'Bobbi'; +$aFirstNames[] = 'Maritza'; +$aFirstNames[] = 'Lucile'; +$aFirstNames[] = 'Leanne'; +$aFirstNames[] = 'Jeannine'; +$aFirstNames[] = 'Deana'; +$aFirstNames[] = 'Aileen'; +$aFirstNames[] = 'Lorie'; +$aFirstNames[] = 'Ladonna'; +$aFirstNames[] = 'Willa'; +$aFirstNames[] = 'Manuela'; +$aFirstNames[] = 'Gale'; +$aFirstNames[] = 'Selma'; +$aFirstNames[] = 'Dolly'; +$aFirstNames[] = 'Sybil'; +$aFirstNames[] = 'Abby'; +$aFirstNames[] = 'Lara'; +$aFirstNames[] = 'Dale'; +$aFirstNames[] = 'Ivy'; +$aFirstNames[] = 'Dee'; +$aFirstNames[] = 'Winnie'; +$aFirstNames[] = 'Marcy'; +$aFirstNames[] = 'Luisa'; +$aFirstNames[] = 'Jeri'; +$aFirstNames[] = 'Magdalena'; +$aFirstNames[] = 'Ofelia'; +$aFirstNames[] = 'Meagan'; +$aFirstNames[] = 'Audra'; +$aFirstNames[] = 'Matilda'; +$aFirstNames[] = 'Leila'; +$aFirstNames[] = 'Cornelia'; +$aFirstNames[] = 'Bianca'; +$aFirstNames[] = 'Simone'; +$aFirstNames[] = 'Bettye'; +$aFirstNames[] = 'Randi'; +$aFirstNames[] = 'Virgie'; +$aFirstNames[] = 'Latisha'; +$aFirstNames[] = 'Barbra'; +$aFirstNames[] = 'Georgina'; +$aFirstNames[] = 'Eliza'; +$aFirstNames[] = 'Leann'; +$aFirstNames[] = 'Bridgette'; +$aFirstNames[] = 'Rhoda'; +$aFirstNames[] = 'Haley'; +$aFirstNames[] = 'Adela'; +$aFirstNames[] = 'Nola'; +$aFirstNames[] = 'Bernadine'; +$aFirstNames[] = 'Flossie'; +$aFirstNames[] = 'Ila'; +$aFirstNames[] = 'Greta'; +$aFirstNames[] = 'Ruthie'; +$aFirstNames[] = 'Nelda'; +$aFirstNames[] = 'Minerva'; +$aFirstNames[] = 'Lilly'; +$aFirstNames[] = 'Terrie'; +$aFirstNames[] = 'Letha'; +$aFirstNames[] = 'Hilary'; +$aFirstNames[] = 'Estela'; +$aFirstNames[] = 'Valarie'; +$aFirstNames[] = 'Brianna'; +$aFirstNames[] = 'Rosalyn'; +$aFirstNames[] = 'Earline'; +$aFirstNames[] = 'Catalina'; +$aFirstNames[] = 'Ava'; +$aFirstNames[] = 'Mia'; +$aFirstNames[] = 'Clarissa'; +$aFirstNames[] = 'Lidia'; +$aFirstNames[] = 'Corrine'; +$aFirstNames[] = 'Alexandria'; +$aFirstNames[] = 'Concepcion'; +$aFirstNames[] = 'Tia'; +$aFirstNames[] = 'Sharron'; +$aFirstNames[] = 'Rae'; +$aFirstNames[] = 'Dona'; +$aFirstNames[] = 'Ericka'; +$aFirstNames[] = 'Jami'; +$aFirstNames[] = 'Elnora'; +$aFirstNames[] = 'Chandra'; +$aFirstNames[] = 'Lenore'; +$aFirstNames[] = 'Neva'; +$aFirstNames[] = 'Marylou'; +$aFirstNames[] = 'Melisa'; +$aFirstNames[] = 'Tabatha'; +$aFirstNames[] = 'Serena'; +$aFirstNames[] = 'Avis'; +$aFirstNames[] = 'Allie'; +$aFirstNames[] = 'Sofia'; +$aFirstNames[] = 'Jeanie'; +$aFirstNames[] = 'Odessa'; +$aFirstNames[] = 'Nannie'; +$aFirstNames[] = 'Harriett'; +$aFirstNames[] = 'James'; +$aFirstNames[] = 'John'; +$aFirstNames[] = 'Robert'; +$aFirstNames[] = 'Michael'; +$aFirstNames[] = 'William'; +$aFirstNames[] = 'David'; +$aFirstNames[] = 'Richard'; +$aFirstNames[] = 'Charles'; +$aFirstNames[] = 'Joseph'; +$aFirstNames[] = 'Thomas'; +$aFirstNames[] = 'Christopher'; +$aFirstNames[] = 'Daniel'; +$aFirstNames[] = 'Paul'; +$aFirstNames[] = 'Mark'; +$aFirstNames[] = 'Donald'; +$aFirstNames[] = 'George'; +$aFirstNames[] = 'Kenneth'; +$aFirstNames[] = 'Steven'; +$aFirstNames[] = 'Edward'; +$aFirstNames[] = 'Brian'; +$aFirstNames[] = 'Ronald'; +$aFirstNames[] = 'Anthony'; +$aFirstNames[] = 'Kevin'; +$aFirstNames[] = 'Jason'; +$aFirstNames[] = 'Matthew'; +$aFirstNames[] = 'Gary'; +$aFirstNames[] = 'Timothy'; +$aFirstNames[] = 'Jose'; +$aFirstNames[] = 'Larry'; +$aFirstNames[] = 'Jeffrey'; +$aFirstNames[] = 'Frank'; +$aFirstNames[] = 'Scott'; +$aFirstNames[] = 'Eric'; +$aFirstNames[] = 'Stephen'; +$aFirstNames[] = 'Andrew'; +$aFirstNames[] = 'Raymond'; +$aFirstNames[] = 'Gregory'; +$aFirstNames[] = 'Joshua'; +$aFirstNames[] = 'Jerry'; +$aFirstNames[] = 'Dennis'; +$aFirstNames[] = 'Walter'; +$aFirstNames[] = 'Patrick'; +$aFirstNames[] = 'Peter'; +$aFirstNames[] = 'Harold'; +$aFirstNames[] = 'Douglas'; +$aFirstNames[] = 'Henry'; +$aFirstNames[] = 'Carl'; +$aFirstNames[] = 'Arthur'; +$aFirstNames[] = 'Ryan'; +$aFirstNames[] = 'Roger'; +$aFirstNames[] = 'Joe'; +$aFirstNames[] = 'Juan'; +$aFirstNames[] = 'Jack'; +$aFirstNames[] = 'Albert'; +$aFirstNames[] = 'Jonathan'; +$aFirstNames[] = 'Justin'; +$aFirstNames[] = 'Terry'; +$aFirstNames[] = 'Gerald'; +$aFirstNames[] = 'Keith'; +$aFirstNames[] = 'Samuel'; +$aFirstNames[] = 'Willie'; +$aFirstNames[] = 'Ralph'; +$aFirstNames[] = 'Lawrence'; +$aFirstNames[] = 'Nicholas'; +$aFirstNames[] = 'Roy'; +$aFirstNames[] = 'Benjamin'; +$aFirstNames[] = 'Bruce'; +$aFirstNames[] = 'Brandon'; +$aFirstNames[] = 'Adam'; +$aFirstNames[] = 'Harry'; +$aFirstNames[] = 'Fred'; +$aFirstNames[] = 'Wayne'; +$aFirstNames[] = 'Billy'; +$aFirstNames[] = 'Steve'; +$aFirstNames[] = 'Louis'; +$aFirstNames[] = 'Jeremy'; +$aFirstNames[] = 'Aaron'; +$aFirstNames[] = 'Randy'; +$aFirstNames[] = 'Howard'; +$aFirstNames[] = 'Eugene'; +$aFirstNames[] = 'Carlos'; +$aFirstNames[] = 'Russell'; +$aFirstNames[] = 'Bobby'; +$aFirstNames[] = 'Victor'; +$aFirstNames[] = 'Martin'; +$aFirstNames[] = 'Ernest'; +$aFirstNames[] = 'Phillip'; +$aFirstNames[] = 'Todd'; +$aFirstNames[] = 'Jesse'; +$aFirstNames[] = 'Craig'; +$aFirstNames[] = 'Alan'; +$aFirstNames[] = 'Shawn'; +$aFirstNames[] = 'Clarence'; +$aFirstNames[] = 'Sean'; +$aFirstNames[] = 'Philip'; +$aFirstNames[] = 'Chris'; +$aFirstNames[] = 'Johnny'; +$aFirstNames[] = 'Earl'; +$aFirstNames[] = 'Jimmy'; +$aFirstNames[] = 'Antonio'; +$aFirstNames[] = 'Danny'; +$aFirstNames[] = 'Bryan'; +$aFirstNames[] = 'Tony'; +$aFirstNames[] = 'Luis'; +$aFirstNames[] = 'Mike'; +$aFirstNames[] = 'Stanley'; +$aFirstNames[] = 'Leonard'; +$aFirstNames[] = 'Nathan'; +$aFirstNames[] = 'Dale'; +$aFirstNames[] = 'Manuel'; +$aFirstNames[] = 'Rodney'; +$aFirstNames[] = 'Curtis'; +$aFirstNames[] = 'Norman'; +$aFirstNames[] = 'Allen'; +$aFirstNames[] = 'Marvin'; +$aFirstNames[] = 'Vincent'; +$aFirstNames[] = 'Glenn'; +$aFirstNames[] = 'Jeffery'; +$aFirstNames[] = 'Travis'; +$aFirstNames[] = 'Jeff'; +$aFirstNames[] = 'Chad'; +$aFirstNames[] = 'Jacob'; +$aFirstNames[] = 'Lee'; +$aFirstNames[] = 'Melvin'; +$aFirstNames[] = 'Alfred'; +$aFirstNames[] = 'Kyle'; +$aFirstNames[] = 'Francis'; +$aFirstNames[] = 'Bradley'; +$aFirstNames[] = 'Jesus'; +$aFirstNames[] = 'Herbert'; +$aFirstNames[] = 'Frederick'; +$aFirstNames[] = 'Ray'; +$aFirstNames[] = 'Joel'; +$aFirstNames[] = 'Edwin'; +$aFirstNames[] = 'Don'; +$aFirstNames[] = 'Eddie'; +$aFirstNames[] = 'Ricky'; +$aFirstNames[] = 'Troy'; +$aFirstNames[] = 'Randall'; +$aFirstNames[] = 'Barry'; +$aFirstNames[] = 'Alexander'; +$aFirstNames[] = 'Bernard'; +$aFirstNames[] = 'Mario'; +$aFirstNames[] = 'Leroy'; +$aFirstNames[] = 'Francisco'; +$aFirstNames[] = 'Marcus'; +$aFirstNames[] = 'Micheal'; +$aFirstNames[] = 'Theodore'; +$aFirstNames[] = 'Clifford'; +$aFirstNames[] = 'Miguel'; +$aFirstNames[] = 'Oscar'; +$aFirstNames[] = 'Jay'; +$aFirstNames[] = 'Jim'; +$aFirstNames[] = 'Tom'; +$aFirstNames[] = 'Calvin'; +$aFirstNames[] = 'Alex'; +$aFirstNames[] = 'Jon'; +$aFirstNames[] = 'Ronnie'; +$aFirstNames[] = 'Bill'; +$aFirstNames[] = 'Lloyd'; +$aFirstNames[] = 'Tommy'; +$aFirstNames[] = 'Leon'; +$aFirstNames[] = 'Derek'; +$aFirstNames[] = 'Warren'; +$aFirstNames[] = 'Darrell'; +$aFirstNames[] = 'Jerome'; +$aFirstNames[] = 'Floyd'; +$aFirstNames[] = 'Leo'; +$aFirstNames[] = 'Alvin'; +$aFirstNames[] = 'Tim'; +$aFirstNames[] = 'Wesley'; +$aFirstNames[] = 'Gordon'; +$aFirstNames[] = 'Dean'; +$aFirstNames[] = 'Greg'; +$aFirstNames[] = 'Jorge'; +$aFirstNames[] = 'Dustin'; +$aFirstNames[] = 'Pedro'; +$aFirstNames[] = 'Derrick'; +$aFirstNames[] = 'Dan'; +$aFirstNames[] = 'Lewis'; +$aFirstNames[] = 'Zachary'; +$aFirstNames[] = 'Corey'; +$aFirstNames[] = 'Herman'; +$aFirstNames[] = 'Maurice'; +$aFirstNames[] = 'Vernon'; +$aFirstNames[] = 'Roberto'; +$aFirstNames[] = 'Clyde'; +$aFirstNames[] = 'Glen'; +$aFirstNames[] = 'Hector'; +$aFirstNames[] = 'Shane'; +$aFirstNames[] = 'Ricardo'; +$aFirstNames[] = 'Sam'; +$aFirstNames[] = 'Rick'; +$aFirstNames[] = 'Lester'; +$aFirstNames[] = 'Brent'; +$aFirstNames[] = 'Ramon'; +$aFirstNames[] = 'Charlie'; +$aFirstNames[] = 'Tyler'; +$aFirstNames[] = 'Gilbert'; +$aFirstNames[] = 'Gene'; +$aFirstNames[] = 'Marc'; +$aFirstNames[] = 'Reginald'; +$aFirstNames[] = 'Ruben'; +$aFirstNames[] = 'Brett'; +$aFirstNames[] = 'Angel'; +$aFirstNames[] = 'Nathaniel'; +$aFirstNames[] = 'Rafael'; +$aFirstNames[] = 'Leslie'; +$aFirstNames[] = 'Edgar'; +$aFirstNames[] = 'Milton'; +$aFirstNames[] = 'Raul'; +$aFirstNames[] = 'Ben'; +$aFirstNames[] = 'Chester'; +$aFirstNames[] = 'Cecil'; +$aFirstNames[] = 'Duane'; +$aFirstNames[] = 'Franklin'; +$aFirstNames[] = 'Andre'; +$aFirstNames[] = 'Elmer'; +$aFirstNames[] = 'Brad'; +$aFirstNames[] = 'Gabriel'; +$aFirstNames[] = 'Ron'; +$aFirstNames[] = 'Mitchell'; +$aFirstNames[] = 'Roland'; +$aFirstNames[] = 'Arnold'; +$aFirstNames[] = 'Harvey'; +$aFirstNames[] = 'Jared'; +$aFirstNames[] = 'Adrian'; +$aFirstNames[] = 'Karl'; +$aFirstNames[] = 'Cory'; +$aFirstNames[] = 'Claude'; +$aFirstNames[] = 'Erik'; +$aFirstNames[] = 'Darryl'; +$aFirstNames[] = 'Jamie'; +$aFirstNames[] = 'Neil'; +$aFirstNames[] = 'Jessie'; +$aFirstNames[] = 'Christian'; +$aFirstNames[] = 'Javier'; +$aFirstNames[] = 'Fernando'; +$aFirstNames[] = 'Clinton'; +$aFirstNames[] = 'Ted'; +$aFirstNames[] = 'Mathew'; +$aFirstNames[] = 'Tyrone'; +$aFirstNames[] = 'Darren'; +$aFirstNames[] = 'Lonnie'; +$aFirstNames[] = 'Lance'; +$aFirstNames[] = 'Cody'; +$aFirstNames[] = 'Julio'; +$aFirstNames[] = 'Kelly'; +$aFirstNames[] = 'Kurt'; +$aFirstNames[] = 'Allan'; +$aFirstNames[] = 'Nelson'; +$aFirstNames[] = 'Guy'; +$aFirstNames[] = 'Clayton'; +$aFirstNames[] = 'Hugh'; +$aFirstNames[] = 'Max'; +$aFirstNames[] = 'Dwayne'; +$aFirstNames[] = 'Dwight'; +$aFirstNames[] = 'Armando'; +$aFirstNames[] = 'Felix'; +$aFirstNames[] = 'Jimmie'; +$aFirstNames[] = 'Everett'; +$aFirstNames[] = 'Jordan'; +$aFirstNames[] = 'Ian'; +$aFirstNames[] = 'Wallace'; +$aFirstNames[] = 'Ken'; +$aFirstNames[] = 'Bob'; +$aFirstNames[] = 'Jaime'; +$aFirstNames[] = 'Casey'; +$aFirstNames[] = 'Alfredo'; +$aFirstNames[] = 'Alberto'; +$aFirstNames[] = 'Dave'; +$aFirstNames[] = 'Ivan'; +$aFirstNames[] = 'Johnnie'; +$aFirstNames[] = 'Sidney'; +$aFirstNames[] = 'Byron'; +$aFirstNames[] = 'Julian'; +$aFirstNames[] = 'Isaac'; +$aFirstNames[] = 'Morris'; +$aFirstNames[] = 'Clifton'; +$aFirstNames[] = 'Willard'; +$aFirstNames[] = 'Daryl'; +$aFirstNames[] = 'Ross'; +$aFirstNames[] = 'Virgil'; +$aFirstNames[] = 'Andy'; +$aFirstNames[] = 'Marshall'; +$aFirstNames[] = 'Salvador'; +$aFirstNames[] = 'Perry'; +$aFirstNames[] = 'Kirk'; +$aFirstNames[] = 'Sergio'; +$aFirstNames[] = 'Marion'; +$aFirstNames[] = 'Tracy'; +$aFirstNames[] = 'Seth'; +$aFirstNames[] = 'Kent'; +$aFirstNames[] = 'Terrance'; +$aFirstNames[] = 'Rene'; +$aFirstNames[] = 'Eduardo'; +$aFirstNames[] = 'Terrence'; +$aFirstNames[] = 'Enrique'; +$aFirstNames[] = 'Freddie'; +$aFirstNames[] = 'Wade'; +$aFirstNames[] = 'Austin'; +$aFirstNames[] = 'Stuart'; +$aFirstNames[] = 'Fredrick'; +$aFirstNames[] = 'Arturo'; +$aFirstNames[] = 'Alejandro'; +$aFirstNames[] = 'Jackie'; +$aFirstNames[] = 'Joey'; +$aFirstNames[] = 'Nick'; +$aFirstNames[] = 'Luther'; +$aFirstNames[] = 'Wendell'; +$aFirstNames[] = 'Jeremiah'; +$aFirstNames[] = 'Evan'; +$aFirstNames[] = 'Julius'; +$aFirstNames[] = 'Dana'; +$aFirstNames[] = 'Donnie'; +$aFirstNames[] = 'Otis'; +$aFirstNames[] = 'Shannon'; +$aFirstNames[] = 'Trevor'; +$aFirstNames[] = 'Oliver'; +$aFirstNames[] = 'Luke'; +$aFirstNames[] = 'Homer'; +$aFirstNames[] = 'Gerard'; +$aFirstNames[] = 'Doug'; +$aFirstNames[] = 'Kenny'; +$aFirstNames[] = 'Hubert'; +$aFirstNames[] = 'Angelo'; +$aFirstNames[] = 'Shaun'; +$aFirstNames[] = 'Lyle'; +$aFirstNames[] = 'Matt'; +$aFirstNames[] = 'Lynn'; +$aFirstNames[] = 'Alfonso'; +$aFirstNames[] = 'Orlando'; +$aFirstNames[] = 'Rex'; +$aFirstNames[] = 'Carlton'; +$aFirstNames[] = 'Ernesto'; +$aFirstNames[] = 'Cameron'; +$aFirstNames[] = 'Neal'; +$aFirstNames[] = 'Pablo'; +$aFirstNames[] = 'Lorenzo'; +$aFirstNames[] = 'Omar'; +$aFirstNames[] = 'Wilbur'; +$aFirstNames[] = 'Blake'; +$aFirstNames[] = 'Grant'; +$aFirstNames[] = 'Horace'; +$aFirstNames[] = 'Roderick'; +$aFirstNames[] = 'Kerry'; +$aFirstNames[] = 'Abraham'; +$aFirstNames[] = 'Willis'; +$aFirstNames[] = 'Rickey'; +$aFirstNames[] = 'Jean'; +$aFirstNames[] = 'Ira'; +$aFirstNames[] = 'Andres'; +$aFirstNames[] = 'Cesar'; +$aFirstNames[] = 'Johnathan'; +$aFirstNames[] = 'Malcolm'; +$aFirstNames[] = 'Rudolph'; +$aFirstNames[] = 'Damon'; +$aFirstNames[] = 'Kelvin'; +$aFirstNames[] = 'Rudy'; +$aFirstNames[] = 'Preston'; +$aFirstNames[] = 'Alton'; +$aFirstNames[] = 'Archie'; +$aFirstNames[] = 'Marco'; +$aFirstNames[] = 'Wm'; +$aFirstNames[] = 'Pete'; +$aFirstNames[] = 'Randolph'; +$aFirstNames[] = 'Garry'; +$aFirstNames[] = 'Geoffrey'; +$aFirstNames[] = 'Jonathon'; +$aFirstNames[] = 'Felipe'; +$aFirstNames[] = 'Bennie'; +$aFirstNames[] = 'Gerardo'; +$aFirstNames[] = 'Ed'; +$aFirstNames[] = 'Dominic'; +$aFirstNames[] = 'Robin'; +$aFirstNames[] = 'Loren'; +$aFirstNames[] = 'Delbert'; +$aFirstNames[] = 'Colin'; +$aFirstNames[] = 'Guillermo'; +$aFirstNames[] = 'Earnest'; +$aFirstNames[] = 'Lucas'; +$aFirstNames[] = 'Benny'; +$aFirstNames[] = 'Noel'; +$aFirstNames[] = 'Spencer'; +$aFirstNames[] = 'Rodolfo'; +$aFirstNames[] = 'Myron'; +$aFirstNames[] = 'Edmund'; +$aFirstNames[] = 'Garrett'; +$aFirstNames[] = 'Salvatore'; +$aFirstNames[] = 'Cedric'; +$aFirstNames[] = 'Lowell'; +$aFirstNames[] = 'Gregg'; +$aFirstNames[] = 'Sherman'; +$aFirstNames[] = 'Wilson'; +$aFirstNames[] = 'Devin'; +$aFirstNames[] = 'Sylvester'; +$aFirstNames[] = 'Kim'; +$aFirstNames[] = 'Roosevelt'; +$aFirstNames[] = 'Israel'; +$aFirstNames[] = 'Jermaine'; +$aFirstNames[] = 'Forrest'; +$aFirstNames[] = 'Wilbert'; +$aFirstNames[] = 'Leland'; +$aFirstNames[] = 'Simon'; +$aFirstNames[] = 'Guadalupe'; +$aFirstNames[] = 'Clark'; +$aFirstNames[] = 'Irving'; +$aFirstNames[] = 'Carroll'; +$aFirstNames[] = 'Bryant'; +$aFirstNames[] = 'Owen'; +$aFirstNames[] = 'Rufus'; +$aFirstNames[] = 'Woodrow'; +$aFirstNames[] = 'Sammy'; +$aFirstNames[] = 'Kristopher'; +$aFirstNames[] = 'Mack'; +$aFirstNames[] = 'Levi'; +$aFirstNames[] = 'Marcos'; +$aFirstNames[] = 'Gustavo'; +$aFirstNames[] = 'Jake'; +$aFirstNames[] = 'Lionel'; +$aFirstNames[] = 'Marty'; +$aFirstNames[] = 'Taylor'; +$aFirstNames[] = 'Ellis'; +$aFirstNames[] = 'Dallas'; +$aFirstNames[] = 'Gilberto'; +$aFirstNames[] = 'Clint'; +$aFirstNames[] = 'Nicolas'; +$aFirstNames[] = 'Laurence'; +$aFirstNames[] = 'Ismael'; +$aFirstNames[] = 'Orville'; +$aFirstNames[] = 'Drew'; +$aFirstNames[] = 'Jody'; +$aFirstNames[] = 'Ervin'; +$aFirstNames[] = 'Dewey'; +$aFirstNames[] = 'Al'; +$aFirstNames[] = 'Wilfred'; +$aFirstNames[] = 'Josh'; +$aFirstNames[] = 'Hugo'; +$aFirstNames[] = 'Ignacio'; +$aFirstNames[] = 'Caleb'; +$aFirstNames[] = 'Tomas'; +$aFirstNames[] = 'Sheldon'; +$aFirstNames[] = 'Erick'; +$aFirstNames[] = 'Frankie'; +$aFirstNames[] = 'Stewart'; +$aFirstNames[] = 'Doyle'; +$aFirstNames[] = 'Darrel'; +$aFirstNames[] = 'Rogelio'; +$aFirstNames[] = 'Terence'; +$aFirstNames[] = 'Santiago'; +$aFirstNames[] = 'Alonzo'; +$aFirstNames[] = 'Elias'; +$aFirstNames[] = 'Bert'; +$aFirstNames[] = 'Elbert'; +$aFirstNames[] = 'Ramiro'; +$aFirstNames[] = 'Conrad'; +$aFirstNames[] = 'Pat'; +$aFirstNames[] = 'Noah'; +$aFirstNames[] = 'Grady'; +$aFirstNames[] = 'Phil'; +$aFirstNames[] = 'Cornelius'; +$aFirstNames[] = 'Lamar'; +$aFirstNames[] = 'Rolando'; +$aFirstNames[] = 'Clay'; +$aFirstNames[] = 'Percy'; +$aFirstNames[] = 'Dexter'; +$aFirstNames[] = 'Bradford'; +$aFirstNames[] = 'Merle'; +$aFirstNames[] = 'Darin'; +$aFirstNames[] = 'Amos'; +$aFirstNames[] = 'Terrell'; +$aFirstNames[] = 'Moses'; +$aFirstNames[] = 'Irvin'; +$aFirstNames[] = 'Saul'; +$aFirstNames[] = 'Roman'; +$aFirstNames[] = 'Darnell'; +$aFirstNames[] = 'Randal'; +$aFirstNames[] = 'Tommie'; +$aFirstNames[] = 'Timmy'; +$aFirstNames[] = 'Darrin'; +$aFirstNames[] = 'Winston'; +$aFirstNames[] = 'Brendan'; +$aFirstNames[] = 'Toby'; +$aFirstNames[] = 'Van'; +$aFirstNames[] = 'Abel'; +$aFirstNames[] = 'Dominick'; +$aFirstNames[] = 'Boyd'; +$aFirstNames[] = 'Courtney'; +$aFirstNames[] = 'Jan'; +$aFirstNames[] = 'Emilio'; +$aFirstNames[] = 'Elijah'; +$aFirstNames[] = 'Cary'; +$aFirstNames[] = 'Domingo'; +$aFirstNames[] = 'Santos'; +$aFirstNames[] = 'Aubrey'; +$aFirstNames[] = 'Emmett'; +$aFirstNames[] = 'Marlon'; +$aFirstNames[] = 'Emanuel'; +$aFirstNames[] = 'Jerald'; +$aFirstNames[] = 'Edmond'; +$aFirstNames[] = 'Jan Jozef '; +$aFirstNames[] = 'Konrad'; +$aFirstNames[] = 'Lidia'; +$aFirstNames[] = 'Lorenz'; +$aFirstNames[] = 'Otto'; +$aFirstNames[] = 'Piotr'; +$aFirstNames[] = 'Wladyslaw'; + +$aNames = array(); +$aNames[] = 'Smith'; +$aNames[] = 'Johnson'; +$aNames[] = 'Williams'; +$aNames[] = 'Jones'; +$aNames[] = 'Brown'; +$aNames[] = 'Davis'; +$aNames[] = 'Miller'; +$aNames[] = 'Wilson'; +$aNames[] = 'Moore'; +$aNames[] = 'Taylor'; +$aNames[] = 'Anderson'; +$aNames[] = 'Thomas'; +$aNames[] = 'Jackson'; +$aNames[] = 'White'; +$aNames[] = 'Harris'; +$aNames[] = 'Martin'; +$aNames[] = 'Thompson'; +$aNames[] = 'Garcia'; +$aNames[] = 'Martinez'; +$aNames[] = 'Robinson'; +$aNames[] = 'Clark'; +$aNames[] = 'Rodriguez'; +$aNames[] = 'Lewis'; +$aNames[] = 'Lee'; +$aNames[] = 'Walker'; +$aNames[] = 'Hall'; +$aNames[] = 'Allen'; +$aNames[] = 'Young'; +$aNames[] = 'Hernandez'; +$aNames[] = 'King'; +$aNames[] = 'Wright'; +$aNames[] = 'Lopez'; +$aNames[] = 'Hill'; +$aNames[] = 'Scott'; +$aNames[] = 'Green'; +$aNames[] = 'Adams'; +$aNames[] = 'Baker'; +$aNames[] = 'Gonzalez'; +$aNames[] = 'Nelson'; +$aNames[] = 'Carter'; +$aNames[] = 'Mitchell'; +$aNames[] = 'Perez'; +$aNames[] = 'Roberts'; +$aNames[] = 'Turner'; +$aNames[] = 'Phillips'; +$aNames[] = 'Campbell'; +$aNames[] = 'Parker'; +$aNames[] = 'Evans'; +$aNames[] = 'Edwards'; +$aNames[] = 'Collins'; +$aNames[] = 'Stewart'; +$aNames[] = 'Sanchez'; +$aNames[] = 'Morris'; +$aNames[] = 'Rogers'; +$aNames[] = 'Reed'; +$aNames[] = 'Cook'; +$aNames[] = 'Morgan'; +$aNames[] = 'Bell'; +$aNames[] = 'Murphy'; +$aNames[] = 'Bailey'; +$aNames[] = 'Rivera'; +$aNames[] = 'Cooper'; +$aNames[] = 'Richardson'; +$aNames[] = 'Cox'; +$aNames[] = 'Howard'; +$aNames[] = 'Ward'; +$aNames[] = 'Torres'; +$aNames[] = 'Peterson'; +$aNames[] = 'Gray'; +$aNames[] = 'Ramirez'; +$aNames[] = 'James'; +$aNames[] = 'Watson'; +$aNames[] = 'Brooks'; +$aNames[] = 'Kelly'; +$aNames[] = 'Sanders'; +$aNames[] = 'Price'; +$aNames[] = 'Bennett'; +$aNames[] = 'Wood'; +$aNames[] = 'Barnes'; +$aNames[] = 'Ross'; +$aNames[] = 'Henderson'; +$aNames[] = 'Coleman'; +$aNames[] = 'Jenkins'; +$aNames[] = 'Perry'; +$aNames[] = 'Powell'; +$aNames[] = 'Long'; +$aNames[] = 'Patterson'; +$aNames[] = 'Hughes'; +$aNames[] = 'Flores'; +$aNames[] = 'Washington'; +$aNames[] = 'Butler'; +$aNames[] = 'Simmons'; +$aNames[] = 'Foster'; +$aNames[] = 'Gonzales'; +$aNames[] = 'Bryant'; +$aNames[] = 'Alexander'; +$aNames[] = 'Russell'; +$aNames[] = 'Griffin'; +$aNames[] = 'Diaz'; +$aNames[] = 'Hayes'; +$aNames[] = 'Myers'; +$aNames[] = 'Ford'; +$aNames[] = 'Hamilton'; +$aNames[] = 'Graham'; +$aNames[] = 'Sullivan'; +$aNames[] = 'Wallace'; +$aNames[] = 'Woods'; +$aNames[] = 'Cole'; +$aNames[] = 'West'; +$aNames[] = 'Jordan'; +$aNames[] = 'Owens'; +$aNames[] = 'Reynolds'; +$aNames[] = 'Fisher'; +$aNames[] = 'Ellis'; +$aNames[] = 'Harrison'; +$aNames[] = 'Gibson'; +$aNames[] = 'Mcdonald'; +$aNames[] = 'Cruz'; +$aNames[] = 'Marshall'; +$aNames[] = 'Ortiz'; +$aNames[] = 'Gomez'; +$aNames[] = 'Murray'; +$aNames[] = 'Freeman'; +$aNames[] = 'Wells'; +$aNames[] = 'Webb'; +$aNames[] = 'Simpson'; +$aNames[] = 'Stevens'; +$aNames[] = 'Tucker'; +$aNames[] = 'Porter'; +$aNames[] = 'Hunter'; +$aNames[] = 'Hicks'; +$aNames[] = 'Crawford'; +$aNames[] = 'Henry'; +$aNames[] = 'Boyd'; +$aNames[] = 'Mason'; +$aNames[] = 'Morales'; +$aNames[] = 'Kennedy'; +$aNames[] = 'Warren'; +$aNames[] = 'Dixon'; +$aNames[] = 'Ramos'; +$aNames[] = 'Reyes'; +$aNames[] = 'Burns'; +$aNames[] = 'Gordon'; +$aNames[] = 'Shaw'; +$aNames[] = 'Holmes'; +$aNames[] = 'Rice'; +$aNames[] = 'Robertson'; +$aNames[] = 'Hunt'; +$aNames[] = 'Black'; +$aNames[] = 'Daniels'; +$aNames[] = 'Palmer'; +$aNames[] = 'Mills'; +$aNames[] = 'Nichols'; +$aNames[] = 'Grant'; +$aNames[] = 'Knight'; +$aNames[] = 'Ferguson'; +$aNames[] = 'Rose'; +$aNames[] = 'Stone'; +$aNames[] = 'Hawkins'; +$aNames[] = 'Dunn'; +$aNames[] = 'Perkins'; +$aNames[] = 'Hudson'; +$aNames[] = 'Spencer'; +$aNames[] = 'Gardner'; +$aNames[] = 'Stephens'; +$aNames[] = 'Payne'; +$aNames[] = 'Pierce'; +$aNames[] = 'Berry'; +$aNames[] = 'Matthews'; +$aNames[] = 'Arnold'; +$aNames[] = 'Wagner'; +$aNames[] = 'Willis'; +$aNames[] = 'Ray'; +$aNames[] = 'Watkins'; +$aNames[] = 'Olson'; +$aNames[] = 'Carroll'; +$aNames[] = 'Duncan'; +$aNames[] = 'Snyder'; +$aNames[] = 'Hart'; +$aNames[] = 'Cunningham'; +$aNames[] = 'Bradley'; +$aNames[] = 'Lane'; +$aNames[] = 'Andrews'; +$aNames[] = 'Ruiz'; +$aNames[] = 'Harper'; +$aNames[] = 'Fox'; +$aNames[] = 'Riley'; +$aNames[] = 'Armstrong'; +$aNames[] = 'Carpenter'; +$aNames[] = 'Weaver'; +$aNames[] = 'Greene'; +$aNames[] = 'Lawrence'; +$aNames[] = 'Elliott'; +$aNames[] = 'Chavez'; +$aNames[] = 'Sims'; +$aNames[] = 'Austin'; +$aNames[] = 'Peters'; +$aNames[] = 'Kelley'; +$aNames[] = 'Franklin'; +$aNames[] = 'Lawson'; +$aNames[] = 'Fields'; +$aNames[] = 'Gutierrez'; +$aNames[] = 'Ryan'; +$aNames[] = 'Schmidt'; +$aNames[] = 'Carr'; +$aNames[] = 'Vasquez'; +$aNames[] = 'Castillo'; +$aNames[] = 'Wheeler'; +$aNames[] = 'Chapman'; +$aNames[] = 'Oliver'; +$aNames[] = 'Montgomery'; +$aNames[] = 'Richards'; +$aNames[] = 'Williamson'; +$aNames[] = 'Johnston'; +$aNames[] = 'Banks'; +$aNames[] = 'Meyer'; +$aNames[] = 'Bishop'; +$aNames[] = 'Mccoy'; +$aNames[] = 'Howell'; +$aNames[] = 'Alvarez'; +$aNames[] = 'Morrison'; +$aNames[] = 'Hansen'; +$aNames[] = 'Fernandez'; +$aNames[] = 'Garza'; +$aNames[] = 'Harvey'; +$aNames[] = 'Little'; +$aNames[] = 'Burton'; +$aNames[] = 'Stanley'; +$aNames[] = 'Nguyen'; +$aNames[] = 'George'; +$aNames[] = 'Jacobs'; +$aNames[] = 'Reid'; +$aNames[] = 'Kim'; +$aNames[] = 'Fuller'; +$aNames[] = 'Lynch'; +$aNames[] = 'Dean'; +$aNames[] = 'Gilbert'; +$aNames[] = 'Garrett'; +$aNames[] = 'Romero'; +$aNames[] = 'Welch'; +$aNames[] = 'Larson'; +$aNames[] = 'Frazier'; +$aNames[] = 'Burke'; +$aNames[] = 'Hanson'; +$aNames[] = 'Day'; +$aNames[] = 'Mendoza'; +$aNames[] = 'Moreno'; +$aNames[] = 'Bowman'; +$aNames[] = 'Medina'; +$aNames[] = 'Fowler'; +$aNames[] = 'Brewer'; +$aNames[] = 'Hoffman'; +$aNames[] = 'Carlson'; +$aNames[] = 'Silva'; +$aNames[] = 'Pearson'; +$aNames[] = 'Holland'; +$aNames[] = 'Douglas'; +$aNames[] = 'Fleming'; +$aNames[] = 'Jensen'; +$aNames[] = 'Vargas'; +$aNames[] = 'Byrd'; +$aNames[] = 'Davidson'; +$aNames[] = 'Hopkins'; +$aNames[] = 'May'; +$aNames[] = 'Terry'; +$aNames[] = 'Herrera'; +$aNames[] = 'Wade'; +$aNames[] = 'Soto'; +$aNames[] = 'Walters'; +$aNames[] = 'Curtis'; +$aNames[] = 'Neal'; +$aNames[] = 'Caldwell'; +$aNames[] = 'Lowe'; +$aNames[] = 'Jennings'; +$aNames[] = 'Barnett'; +$aNames[] = 'Graves'; +$aNames[] = 'Jimenez'; +$aNames[] = 'Horton'; +$aNames[] = 'Shelton'; +$aNames[] = 'Barrett'; +$aNames[] = 'Obrien'; +$aNames[] = 'Castro'; +$aNames[] = 'Sutton'; +$aNames[] = 'Gregory'; +$aNames[] = 'Mckinney'; +$aNames[] = 'Lucas'; +$aNames[] = 'Miles'; +$aNames[] = 'Craig'; +$aNames[] = 'Rodriquez'; +$aNames[] = 'Chambers'; +$aNames[] = 'Holt'; +$aNames[] = 'Lambert'; +$aNames[] = 'Fletcher'; +$aNames[] = 'Watts'; +$aNames[] = 'Bates'; +$aNames[] = 'Hale'; +$aNames[] = 'Rhodes'; +$aNames[] = 'Pena'; +$aNames[] = 'Beck'; +$aNames[] = 'Newman'; +$aNames[] = 'Haynes'; +$aNames[] = 'Mcdaniel'; +$aNames[] = 'Mendez'; +$aNames[] = 'Bush'; +$aNames[] = 'Vaughn'; +$aNames[] = 'Parks'; +$aNames[] = 'Dawson'; +$aNames[] = 'Santiago'; +$aNames[] = 'Norris'; +$aNames[] = 'Hardy'; +$aNames[] = 'Love'; +$aNames[] = 'Steele'; +$aNames[] = 'Curry'; +$aNames[] = 'Powers'; +$aNames[] = 'Schultz'; +$aNames[] = 'Barker'; +$aNames[] = 'Guzman'; +$aNames[] = 'Page'; +$aNames[] = 'Munoz'; +$aNames[] = 'Ball'; +$aNames[] = 'Keller'; +$aNames[] = 'Chandler'; +$aNames[] = 'Weber'; +$aNames[] = 'Leonard'; +$aNames[] = 'Walsh'; +$aNames[] = 'Lyons'; +$aNames[] = 'Ramsey'; +$aNames[] = 'Wolfe'; +$aNames[] = 'Schneider'; +$aNames[] = 'Mullins'; +$aNames[] = 'Benson'; +$aNames[] = 'Sharp'; +$aNames[] = 'Bowen'; +$aNames[] = 'Daniel'; +$aNames[] = 'Barber'; +$aNames[] = 'Cummings'; +$aNames[] = 'Hines'; +$aNames[] = 'Baldwin'; +$aNames[] = 'Griffith'; +$aNames[] = 'Valdez'; +$aNames[] = 'Hubbard'; +$aNames[] = 'Salazar'; +$aNames[] = 'Reeves'; +$aNames[] = 'Warner'; +$aNames[] = 'Stevenson'; +$aNames[] = 'Burgess'; +$aNames[] = 'Santos'; +$aNames[] = 'Tate'; +$aNames[] = 'Cross'; +$aNames[] = 'Garner'; +$aNames[] = 'Mann'; +$aNames[] = 'Mack'; +$aNames[] = 'Moss'; +$aNames[] = 'Thornton'; +$aNames[] = 'Dennis'; +$aNames[] = 'Mcgee'; +$aNames[] = 'Farmer'; +$aNames[] = 'Delgado'; +$aNames[] = 'Aguilar'; +$aNames[] = 'Vega'; +$aNames[] = 'Glover'; +$aNames[] = 'Manning'; +$aNames[] = 'Cohen'; +$aNames[] = 'Harmon'; +$aNames[] = 'Rodgers'; +$aNames[] = 'Robbins'; +$aNames[] = 'Newton'; +$aNames[] = 'Todd'; +$aNames[] = 'Blair'; +$aNames[] = 'Higgins'; +$aNames[] = 'Ingram'; +$aNames[] = 'Reese'; +$aNames[] = 'Cannon'; +$aNames[] = 'Strickland'; +$aNames[] = 'Townsend'; +$aNames[] = 'Potter'; +$aNames[] = 'Goodwin'; +$aNames[] = 'Walton'; +$aNames[] = 'Rowe'; +$aNames[] = 'Hampton'; +$aNames[] = 'Ortega'; +$aNames[] = 'Patton'; +$aNames[] = 'Swanson'; +$aNames[] = 'Joseph'; +$aNames[] = 'Francis'; +$aNames[] = 'Goodman'; +$aNames[] = 'Maldonado'; +$aNames[] = 'Yates'; +$aNames[] = 'Becker'; +$aNames[] = 'Erickson'; +$aNames[] = 'Hodges'; +$aNames[] = 'Rios'; +$aNames[] = 'Conner'; +$aNames[] = 'Adkins'; +$aNames[] = 'Webster'; +$aNames[] = 'Norman'; +$aNames[] = 'Malone'; +$aNames[] = 'Hammond'; +$aNames[] = 'Flowers'; +$aNames[] = 'Cobb'; +$aNames[] = 'Moody'; +$aNames[] = 'Quinn'; +$aNames[] = 'Blake'; +$aNames[] = 'Maxwell'; +$aNames[] = 'Pope'; +$aNames[] = 'Floyd'; +$aNames[] = 'Osborne'; +$aNames[] = 'Paul'; +$aNames[] = 'Mccarthy'; +$aNames[] = 'Guerrero'; +$aNames[] = 'Lindsey'; +$aNames[] = 'Estrada'; +$aNames[] = 'Sandoval'; +$aNames[] = 'Gibbs'; +$aNames[] = 'Tyler'; +$aNames[] = 'Gross'; +$aNames[] = 'Fitzgerald'; +$aNames[] = 'Stokes'; +$aNames[] = 'Doyle'; +$aNames[] = 'Sherman'; +$aNames[] = 'Saunders'; +$aNames[] = 'Wise'; +$aNames[] = 'Colon'; +$aNames[] = 'Gill'; +$aNames[] = 'Alvarado'; +$aNames[] = 'Greer'; +$aNames[] = 'Padilla'; +$aNames[] = 'Simon'; +$aNames[] = 'Waters'; +$aNames[] = 'Nunez'; +$aNames[] = 'Ballard'; +$aNames[] = 'Schwartz'; +$aNames[] = 'Mcbride'; +$aNames[] = 'Houston'; +$aNames[] = 'Christensen'; +$aNames[] = 'Klein'; +$aNames[] = 'Pratt'; +$aNames[] = 'Briggs'; +$aNames[] = 'Parsons'; +$aNames[] = 'Mclaughlin'; +$aNames[] = 'Zimmerman'; +$aNames[] = 'French'; +$aNames[] = 'Buchanan'; +$aNames[] = 'Moran'; +$aNames[] = 'Copeland'; +$aNames[] = 'Roy'; +$aNames[] = 'Pittman'; +$aNames[] = 'Brady'; +$aNames[] = 'Mccormick'; +$aNames[] = 'Holloway'; +$aNames[] = 'Brock'; +$aNames[] = 'Poole'; +$aNames[] = 'Frank'; +$aNames[] = 'Logan'; +$aNames[] = 'Owen'; +$aNames[] = 'Bass'; +$aNames[] = 'Marsh'; +$aNames[] = 'Drake'; +$aNames[] = 'Wong'; +$aNames[] = 'Jefferson'; +$aNames[] = 'Park'; +$aNames[] = 'Morton'; +$aNames[] = 'Abbott'; +$aNames[] = 'Sparks'; +$aNames[] = 'Patrick'; +$aNames[] = 'Norton'; +$aNames[] = 'Huff'; +$aNames[] = 'Clayton'; +$aNames[] = 'Massey'; +$aNames[] = 'Lloyd'; +$aNames[] = 'Figueroa'; +$aNames[] = 'Carson'; +$aNames[] = 'Bowers'; +$aNames[] = 'Roberson'; +$aNames[] = 'Barton'; +$aNames[] = 'Tran'; +$aNames[] = 'Lamb'; +$aNames[] = 'Harrington'; +$aNames[] = 'Casey'; +$aNames[] = 'Boone'; +$aNames[] = 'Cortez'; +$aNames[] = 'Clarke'; +$aNames[] = 'Mathis'; +$aNames[] = 'Singleton'; +$aNames[] = 'Wilkins'; +$aNames[] = 'Cain'; +$aNames[] = 'Bryan'; +$aNames[] = 'Underwood'; +$aNames[] = 'Hogan'; +$aNames[] = 'Mckenzie'; +$aNames[] = 'Collier'; +$aNames[] = 'Luna'; +$aNames[] = 'Phelps'; +$aNames[] = 'Mcguire'; +$aNames[] = 'Allison'; +$aNames[] = 'Bridges'; +$aNames[] = 'Wilkerson'; +$aNames[] = 'Nash'; +$aNames[] = 'Summers'; +$aNames[] = 'Atkins'; +$aNames[] = 'Wilcox'; +$aNames[] = 'Pitts'; +$aNames[] = 'Conley'; +$aNames[] = 'Marquez'; +$aNames[] = 'Burnett'; +$aNames[] = 'Richard'; +$aNames[] = 'Cochran'; +$aNames[] = 'Chase'; +$aNames[] = 'Davenport'; +$aNames[] = 'Hood'; +$aNames[] = 'Gates'; +$aNames[] = 'Clay'; +$aNames[] = 'Ayala'; +$aNames[] = 'Sawyer'; +$aNames[] = 'Roman'; +$aNames[] = 'Vazquez'; +$aNames[] = 'Dickerson'; +$aNames[] = 'Hodge'; +$aNames[] = 'Acosta'; +$aNames[] = 'Flynn'; +$aNames[] = 'Espinoza'; +$aNames[] = 'Nicholson'; +$aNames[] = 'Monroe'; +$aNames[] = 'Wolf'; +$aNames[] = 'Morrow'; +$aNames[] = 'Kirk'; +$aNames[] = 'Randall'; +$aNames[] = 'Anthony'; +$aNames[] = 'Whitaker'; +$aNames[] = 'Oconnor'; +$aNames[] = 'Skinner'; +$aNames[] = 'Ware'; +$aNames[] = 'Molina'; +$aNames[] = 'Kirby'; +$aNames[] = 'Huffman'; +$aNames[] = 'Bradford'; +$aNames[] = 'Charles'; +$aNames[] = 'Gilmore'; +$aNames[] = 'Dominguez'; +$aNames[] = 'Oneal'; +$aNames[] = 'Bruce'; +$aNames[] = 'Lang'; +$aNames[] = 'Combs'; +$aNames[] = 'Kramer'; +$aNames[] = 'Heath'; +$aNames[] = 'Hancock'; +$aNames[] = 'Gallagher'; +$aNames[] = 'Gaines'; +$aNames[] = 'Shaffer'; +$aNames[] = 'Short'; +$aNames[] = 'Wiggins'; +$aNames[] = 'Mathews'; +$aNames[] = 'Mcclain'; +$aNames[] = 'Fischer'; +$aNames[] = 'Wall'; +$aNames[] = 'Small'; +$aNames[] = 'Melton'; +$aNames[] = 'Hensley'; +$aNames[] = 'Bond'; +$aNames[] = 'Dyer'; +$aNames[] = 'Cameron'; +$aNames[] = 'Grimes'; +$aNames[] = 'Contreras'; +$aNames[] = 'Christian'; +$aNames[] = 'Wyatt'; +$aNames[] = 'Baxter'; +$aNames[] = 'Snow'; +$aNames[] = 'Mosley'; +$aNames[] = 'Shepherd'; +$aNames[] = 'Larsen'; +$aNames[] = 'Hoover'; +$aNames[] = 'Beasley'; +$aNames[] = 'Glenn'; +$aNames[] = 'Petersen'; +$aNames[] = 'Whitehead'; +$aNames[] = 'Meyers'; +$aNames[] = 'Keith'; +$aNames[] = 'Garrison'; +$aNames[] = 'Vincent'; +$aNames[] = 'Shields'; +$aNames[] = 'Horn'; +$aNames[] = 'Savage'; +$aNames[] = 'Olsen'; +$aNames[] = 'Schroeder'; +$aNames[] = 'Hartman'; +$aNames[] = 'Woodard'; +$aNames[] = 'Mueller'; +$aNames[] = 'Kemp'; +$aNames[] = 'Deleon'; +$aNames[] = 'Booth'; +$aNames[] = 'Patel'; +$aNames[] = 'Calhoun'; +$aNames[] = 'Wiley'; +$aNames[] = 'Eaton'; +$aNames[] = 'Cline'; +$aNames[] = 'Navarro'; +$aNames[] = 'Harrell'; +$aNames[] = 'Lester'; +$aNames[] = 'Humphrey'; +$aNames[] = 'Parrish'; +$aNames[] = 'Duran'; +$aNames[] = 'Hutchinson'; +$aNames[] = 'Hess'; +$aNames[] = 'Dorsey'; +$aNames[] = 'Bullock'; +$aNames[] = 'Robles'; +$aNames[] = 'Beard'; +$aNames[] = 'Dalton'; +$aNames[] = 'Avila'; +$aNames[] = 'Vance'; +$aNames[] = 'Rich'; +$aNames[] = 'Blackwell'; +$aNames[] = 'York'; +$aNames[] = 'Johns'; +$aNames[] = 'Blankenship'; +$aNames[] = 'Trevino'; +$aNames[] = 'Salinas'; +$aNames[] = 'Campos'; +$aNames[] = 'Pruitt'; +$aNames[] = 'Moses'; +$aNames[] = 'Callahan'; +$aNames[] = 'Golden'; +$aNames[] = 'Montoya'; +$aNames[] = 'Hardin'; +$aNames[] = 'Guerra'; +$aNames[] = 'Mcdowell'; +$aNames[] = 'Carey'; +$aNames[] = 'Stafford'; +$aNames[] = 'Gallegos'; +$aNames[] = 'Henson'; +$aNames[] = 'Wilkinson'; +$aNames[] = 'Booker'; +$aNames[] = 'Merritt'; +$aNames[] = 'Miranda'; +$aNames[] = 'Atkinson'; +$aNames[] = 'Orr'; +$aNames[] = 'Decker'; +$aNames[] = 'Hobbs'; +$aNames[] = 'Preston'; +$aNames[] = 'Tanner'; +$aNames[] = 'Knox'; +$aNames[] = 'Pacheco'; +$aNames[] = 'Stephenson'; +$aNames[] = 'Glass'; +$aNames[] = 'Rojas'; +$aNames[] = 'Serrano'; +$aNames[] = 'Marks'; +$aNames[] = 'Hickman'; +$aNames[] = 'English'; +$aNames[] = 'Sweeney'; +$aNames[] = 'Strong'; +$aNames[] = 'Prince'; +$aNames[] = 'Mcclure'; +$aNames[] = 'Conway'; +$aNames[] = 'Walter'; +$aNames[] = 'Roth'; +$aNames[] = 'Maynard'; +$aNames[] = 'Farrell'; +$aNames[] = 'Lowery'; +$aNames[] = 'Hurst'; +$aNames[] = 'Nixon'; +$aNames[] = 'Weiss'; +$aNames[] = 'Trujillo'; +$aNames[] = 'Ellison'; +$aNames[] = 'Sloan'; +$aNames[] = 'Juarez'; +$aNames[] = 'Winters'; +$aNames[] = 'Mclean'; +$aNames[] = 'Randolph'; +$aNames[] = 'Leon'; +$aNames[] = 'Boyer'; +$aNames[] = 'Villarreal'; +$aNames[] = 'Mccall'; +$aNames[] = 'Gentry'; +$aNames[] = 'Carrillo'; +$aNames[] = 'Kent'; +$aNames[] = 'Ayers'; +$aNames[] = 'Lara'; +$aNames[] = 'Shannon'; +$aNames[] = 'Sexton'; +$aNames[] = 'Pace'; +$aNames[] = 'Hull'; +$aNames[] = 'Leblanc'; +$aNames[] = 'Browning'; +$aNames[] = 'Velasquez'; +$aNames[] = 'Leach'; +$aNames[] = 'Chang'; +$aNames[] = 'House'; +$aNames[] = 'Sellers'; +$aNames[] = 'Herring'; +$aNames[] = 'Noble'; +$aNames[] = 'Foley'; +$aNames[] = 'Bartlett'; +$aNames[] = 'Mercado'; +$aNames[] = 'Landry'; +$aNames[] = 'Durham'; +$aNames[] = 'Walls'; +$aNames[] = 'Barr'; +$aNames[] = 'Mckee'; +$aNames[] = 'Bauer'; +$aNames[] = 'Rivers'; +$aNames[] = 'Everett'; +$aNames[] = 'Bradshaw'; +$aNames[] = 'Pugh'; +$aNames[] = 'Velez'; +$aNames[] = 'Rush'; +$aNames[] = 'Estes'; +$aNames[] = 'Dodson'; +$aNames[] = 'Morse'; +$aNames[] = 'Sheppard'; +$aNames[] = 'Weeks'; +$aNames[] = 'Camacho'; +$aNames[] = 'Bean'; +$aNames[] = 'Barron'; +$aNames[] = 'Livingston'; +$aNames[] = 'Middleton'; +$aNames[] = 'Spears'; +$aNames[] = 'Branch'; +$aNames[] = 'Blevins'; +$aNames[] = 'Chen'; +$aNames[] = 'Kerr'; +$aNames[] = 'Mcconnell'; +$aNames[] = 'Hatfield'; +$aNames[] = 'Harding'; +$aNames[] = 'Ashley'; +$aNames[] = 'Solis'; +$aNames[] = 'Herman'; +$aNames[] = 'Frost'; +$aNames[] = 'Giles'; +$aNames[] = 'Blackburn'; +$aNames[] = 'William'; +$aNames[] = 'Pennington'; +$aNames[] = 'Woodward'; +$aNames[] = 'Finley'; +$aNames[] = 'Mcintosh'; +$aNames[] = 'Koch'; +$aNames[] = 'Best'; +$aNames[] = 'Solomon'; +$aNames[] = 'Mccullough'; +$aNames[] = 'Dudley'; +$aNames[] = 'Nolan'; +$aNames[] = 'Blanchard'; +$aNames[] = 'Rivas'; +$aNames[] = 'Brennan'; +$aNames[] = 'Mejia'; +$aNames[] = 'Kane'; +$aNames[] = 'Benton'; +$aNames[] = 'Joyce'; +$aNames[] = 'Buckley'; +$aNames[] = 'Haley'; +$aNames[] = 'Valentine'; +$aNames[] = 'Maddox'; +$aNames[] = 'Russo'; +$aNames[] = 'Mcknight'; +$aNames[] = 'Buck'; +$aNames[] = 'Moon'; +$aNames[] = 'Mcmillan'; +$aNames[] = 'Crosby'; +$aNames[] = 'Berg'; +$aNames[] = 'Dotson'; +$aNames[] = 'Mays'; +$aNames[] = 'Roach'; +$aNames[] = 'Church'; +$aNames[] = 'Chan'; +$aNames[] = 'Richmond'; +$aNames[] = 'Meadows'; +$aNames[] = 'Faulkner'; +$aNames[] = 'Oneill'; +$aNames[] = 'Knapp'; +$aNames[] = 'Kline'; +$aNames[] = 'Barry'; +$aNames[] = 'Ochoa'; +$aNames[] = 'Jacobson'; +$aNames[] = 'Gay'; +$aNames[] = 'Avery'; +$aNames[] = 'Hendricks'; +$aNames[] = 'Horne'; +$aNames[] = 'Shepard'; +$aNames[] = 'Hebert'; +$aNames[] = 'Cherry'; +$aNames[] = 'Cardenas'; +$aNames[] = 'Mcintyre'; +$aNames[] = 'Whitney'; +$aNames[] = 'Waller'; +$aNames[] = 'Holman'; +$aNames[] = 'Donaldson'; +$aNames[] = 'Cantu'; +$aNames[] = 'Terrell'; +$aNames[] = 'Morin'; +$aNames[] = 'Gillespie'; +$aNames[] = 'Fuentes'; +$aNames[] = 'Tillman'; +$aNames[] = 'Sanford'; +$aNames[] = 'Bentley'; +$aNames[] = 'Peck'; +$aNames[] = 'Key'; +$aNames[] = 'Salas'; +$aNames[] = 'Rollins'; +$aNames[] = 'Gamble'; +$aNames[] = 'Dickson'; +$aNames[] = 'Battle'; +$aNames[] = 'Santana'; +$aNames[] = 'Cabrera'; +$aNames[] = 'Cervantes'; +$aNames[] = 'Howe'; +$aNames[] = 'Hinton'; +$aNames[] = 'Hurley'; +$aNames[] = 'Spence'; +$aNames[] = 'Zamora'; +$aNames[] = 'Yang'; +$aNames[] = 'Mcneil'; +$aNames[] = 'Suarez'; +$aNames[] = 'Case'; +$aNames[] = 'Petty'; +$aNames[] = 'Gould'; +$aNames[] = 'Mcfarland'; +$aNames[] = 'Sampson'; +$aNames[] = 'Carver'; +$aNames[] = 'Bray'; +$aNames[] = 'Rosario'; +$aNames[] = 'Macdonald'; +$aNames[] = 'Stout'; +$aNames[] = 'Hester'; +$aNames[] = 'Melendez'; +$aNames[] = 'Dillon'; +$aNames[] = 'Farley'; +$aNames[] = 'Hopper'; +$aNames[] = 'Galloway'; +$aNames[] = 'Potts'; +$aNames[] = 'Bernard'; +$aNames[] = 'Joyner'; +$aNames[] = 'Stein'; +$aNames[] = 'Aguirre'; +$aNames[] = 'Osborn'; +$aNames[] = 'Mercer'; +$aNames[] = 'Bender'; +$aNames[] = 'Franco'; +$aNames[] = 'Rowland'; +$aNames[] = 'Sykes'; +$aNames[] = 'Benjamin'; +$aNames[] = 'Travis'; +$aNames[] = 'Pickett'; +$aNames[] = 'Crane'; +$aNames[] = 'Sears'; +$aNames[] = 'Mayo'; +$aNames[] = 'Dunlap'; +$aNames[] = 'Hayden'; +$aNames[] = 'Wilder'; +$aNames[] = 'Mckay'; +$aNames[] = 'Coffey'; +$aNames[] = 'Mccarty'; +$aNames[] = 'Ewing'; +$aNames[] = 'Cooley'; +$aNames[] = 'Vaughan'; +$aNames[] = 'Bonner'; +$aNames[] = 'Cotton'; +$aNames[] = 'Holder'; +$aNames[] = 'Stark'; +$aNames[] = 'Ferrell'; +$aNames[] = 'Cantrell'; +$aNames[] = 'Fulton'; +$aNames[] = 'Lynn'; +$aNames[] = 'Lott'; +$aNames[] = 'Calderon'; +$aNames[] = 'Rosa'; +$aNames[] = 'Pollard'; +$aNames[] = 'Hooper'; +$aNames[] = 'Burch'; +$aNames[] = 'Mullen'; +$aNames[] = 'Fry'; +$aNames[] = 'Riddle'; +$aNames[] = 'Levy'; +$aNames[] = 'David'; +$aNames[] = 'Duke'; +$aNames[] = 'Odonnell'; +$aNames[] = 'Guy'; +$aNames[] = 'Michael'; +$aNames[] = 'Britt'; +$aNames[] = 'Frederick'; +$aNames[] = 'Daugherty'; +$aNames[] = 'Berger'; +$aNames[] = 'Dillard'; +$aNames[] = 'Alston'; +$aNames[] = 'Jarvis'; +$aNames[] = 'Frye'; +$aNames[] = 'Riggs'; +$aNames[] = 'Chaney'; +$aNames[] = 'Odom'; +$aNames[] = 'Duffy'; +$aNames[] = 'Fitzpatrick'; +$aNames[] = 'Valenzuela'; +$aNames[] = 'Merrill'; +$aNames[] = 'Mayer'; +$aNames[] = 'Alford'; +$aNames[] = 'Mcpherson'; +$aNames[] = 'Acevedo'; +$aNames[] = 'Donovan'; +$aNames[] = 'Barrera'; +$aNames[] = 'Albert'; +$aNames[] = 'Cote'; +$aNames[] = 'Reilly'; +$aNames[] = 'Compton'; +$aNames[] = 'Raymond'; +$aNames[] = 'Mooney'; +$aNames[] = 'Mcgowan'; +$aNames[] = 'Craft'; +$aNames[] = 'Cleveland'; +$aNames[] = 'Clemons'; +$aNames[] = 'Wynn'; +$aNames[] = 'Nielsen'; +$aNames[] = 'Baird'; +$aNames[] = 'Stanton'; +$aNames[] = 'Snider'; +$aNames[] = 'Rosales'; +$aNames[] = 'Bright'; +$aNames[] = 'Witt'; +$aNames[] = 'Stuart'; +$aNames[] = 'Hays'; +$aNames[] = 'Holden'; +$aNames[] = 'Rutledge'; +$aNames[] = 'Kinney'; +$aNames[] = 'Clements'; +$aNames[] = 'Castaneda'; +$aNames[] = 'Slater'; +$aNames[] = 'Hahn'; +$aNames[] = 'Emerson'; +$aNames[] = 'Conrad'; +$aNames[] = 'Burks'; +$aNames[] = 'Delaney'; +$aNames[] = 'Pate'; +$aNames[] = 'Lancaster'; +$aNames[] = 'Sweet'; +$aNames[] = 'Justice'; +$aNames[] = 'Tyson'; +$aNames[] = 'Sharpe'; +$aNames[] = 'Whitfield'; +$aNames[] = 'Talley'; +$aNames[] = 'Macias'; +$aNames[] = 'Irwin'; +$aNames[] = 'Burris'; +$aNames[] = 'Ratliff'; +$aNames[] = 'Mccray'; +$aNames[] = 'Madden'; +$aNames[] = 'Kaufman'; +$aNames[] = 'Beach'; +$aNames[] = 'Goff'; +$aNames[] = 'Cash'; +$aNames[] = 'Bolton'; +$aNames[] = 'Mcfadden'; +$aNames[] = 'Levine'; +$aNames[] = 'Good'; +$aNames[] = 'Byers'; +$aNames[] = 'Kirkland'; +$aNames[] = 'Kidd'; +$aNames[] = 'Workman'; +$aNames[] = 'Carney'; +$aNames[] = 'Dale'; +$aNames[] = 'Mcleod'; +$aNames[] = 'Holcomb'; +$aNames[] = 'England'; +$aNames[] = 'Finch'; +$aNames[] = 'Head'; +$aNames[] = 'Burt'; +$aNames[] = 'Hendrix'; +$aNames[] = 'Sosa'; +$aNames[] = 'Haney'; +$aNames[] = 'Franks'; +$aNames[] = 'Sargent'; +$aNames[] = 'Nieves'; +$aNames[] = 'Downs'; +$aNames[] = 'Rasmussen'; +$aNames[] = 'Bird'; +$aNames[] = 'Hewitt'; +$aNames[] = 'Lindsay'; +$aNames[] = 'Le'; +$aNames[] = 'Foreman'; +$aNames[] = 'Valencia'; +$aNames[] = 'Oneil'; +$aNames[] = 'Delacruz'; +$aNames[] = 'Vinson'; +$aNames[] = 'Dejesus'; +$aNames[] = 'Hyde'; +$aNames[] = 'Forbes'; +$aNames[] = 'Gilliam'; +$aNames[] = 'Guthrie'; +$aNames[] = 'Wooten'; +$aNames[] = 'Huber'; +$aNames[] = 'Barlow'; +$aNames[] = 'Boyle'; +$aNames[] = 'Mcmahon'; +$aNames[] = 'Buckner'; +$aNames[] = 'Rocha'; +$aNames[] = 'Puckett'; +$aNames[] = 'Langley'; +$aNames[] = 'Knowles'; +$aNames[] = 'Cooke'; +$aNames[] = 'Velazquez'; +$aNames[] = 'Whitley'; +$aNames[] = 'Noel'; +$aNames[] = 'Vang'; +$aNames[] = 'Shea'; +$aNames[] = 'Rouse'; +$aNames[] = 'Hartley'; +$aNames[] = 'Mayfield'; +$aNames[] = 'Elder'; +$aNames[] = 'Rankin'; +$aNames[] = 'Hanna'; +$aNames[] = 'Cowan'; +$aNames[] = 'Lucero'; +$aNames[] = 'Arroyo'; +$aNames[] = 'Slaughter'; +$aNames[] = 'Haas'; +$aNames[] = 'Oconnell'; +$aNames[] = 'Minor'; +$aNames[] = 'Kendrick'; +$aNames[] = 'Shirley'; +$aNames[] = 'Kendall'; +$aNames[] = 'Boucher'; +$aNames[] = 'Archer'; +$aNames[] = 'Boggs'; +$aNames[] = 'Odell'; +$aNames[] = 'Dougherty'; +$aNames[] = 'Andersen'; +$aNames[] = 'Newell'; +$aNames[] = 'Crowe'; +$aNames[] = 'Wang'; +$aNames[] = 'Friedman'; +$aNames[] = 'Bland'; +$aNames[] = 'Swain'; +$aNames[] = 'Holley'; +$aNames[] = 'Adam'; +$aNames[] = 'Adami'; +$aNames[] = 'Adriaen'; +$aNames[] = 'Adriaensen'; +$aNames[] = 'Adriaenssen'; +$aNames[] = 'Adriaenssens'; +$aNames[] = 'Adriencense'; +$aNames[] = 'Adriensence'; +$aNames[] = 'Adrienssens'; +$aNames[] = 'Aelter'; +$aNames[] = 'Aelterman'; +$aNames[] = 'Aelters'; +$aNames[] = 'Aerens'; +$aNames[] = 'Aerts'; +$aNames[] = 'Aertsens'; +$aNames[] = 'Albumazard'; +$aNames[] = 'Alloo'; +$aNames[] = 'Alsteen'; +$aNames[] = 'Andersson'; +$aNames[] = 'André'; +$aNames[] = 'Andries'; +$aNames[] = 'Andriessen'; +$aNames[] = 'Anthon'; +$aNames[] = 'Antoine'; +$aNames[] = 'Appelbaum'; +$aNames[] = 'Applaer'; +$aNames[] = 'Arimont'; +$aNames[] = 'Arquin'; +$aNames[] = 'Arteman'; +$aNames[] = 'Baert'; +$aNames[] = 'Bartholomeeus'; +$aNames[] = 'Bastien'; +$aNames[] = 'Bastin'; +$aNames[] = 'Baugnet'; +$aNames[] = 'Baugniet'; +$aNames[] = 'Baugniez'; +$aNames[] = 'Bauwens'; +$aNames[] = 'Beauve'; +$aNames[] = 'Beck'; +$aNames[] = 'Beckers'; +$aNames[] = 'Bernard'; +$aNames[] = 'Bertrand'; +$aNames[] = 'Bietmé'; +$aNames[] = 'Blaas'; +$aNames[] = 'Blankaert'; +$aNames[] = 'Blanquaert'; +$aNames[] = 'Blondeel'; +$aNames[] = 'Blondeeuw'; +$aNames[] = 'Blondoo'; +$aNames[] = 'Bodart'; +$aNames[] = 'Bodson'; +$aNames[] = 'Boeck'; +$aNames[] = 'Boesmans'; +$aNames[] = 'Bogaert'; +$aNames[] = 'Bogaerts'; +$aNames[] = 'Bogemans'; +$aNames[] = 'Booghmans'; +$aNames[] = 'Borremans'; +$aNames[] = 'Borsu'; +$aNames[] = 'Borsus'; +$aNames[] = 'Borsut'; +$aNames[] = 'Bosmans'; +$aNames[] = 'Bouch'; +$aNames[] = 'Bouchhout'; +$aNames[] = 'Bouillère'; +$aNames[] = 'Bouillet'; +$aNames[] = 'Boulanger'; +$aNames[] = 'Bourton'; +$aNames[] = 'Bouxin'; +$aNames[] = 'Brasseur'; +$aNames[] = 'Brouck'; +$aNames[] = 'Broucke'; +$aNames[] = 'Broucq'; +$aNames[] = 'Broucque'; +$aNames[] = 'Brouhier'; +$aNames[] = 'Brug'; +$aNames[] = 'Bruggesman'; +$aNames[] = 'Bruynseel'; +$aNames[] = 'Bruynseels'; +$aNames[] = 'Burger'; +$aNames[] = 'Burghgraeve'; +$aNames[] = 'Burgmeester'; +$aNames[] = 'Burton'; +$aNames[] = 'Burtont'; +$aNames[] = 'Buyle'; +$aNames[] = 'Calbert'; +$aNames[] = 'Callebaut'; +$aNames[] = 'Callebert'; +$aNames[] = 'Callebout'; +$aNames[] = 'Camby'; +$aNames[] = 'Cappelaere'; +$aNames[] = 'Cappelaire'; +$aNames[] = 'Cappelier'; +$aNames[] = 'Cappeliez'; +$aNames[] = 'Cappellier'; +$aNames[] = 'Carbonez'; +$aNames[] = 'Carbonnez'; +$aNames[] = 'Carlier'; +$aNames[] = 'Casteau'; +$aNames[] = 'Castel'; +$aNames[] = 'Castiaux'; +$aNames[] = 'Cauderlier'; +$aNames[] = 'Caudron'; +$aNames[] = 'Cauvel'; +$aNames[] = 'Cauvet'; +$aNames[] = 'Cauvin'; +$aNames[] = 'Cavard'; +$aNames[] = 'Ceulemans'; +$aNames[] = 'Chantry'; +$aNames[] = 'Charlier'; +$aNames[] = 'Chêneboit'; +$aNames[] = 'Chestay'; +$aNames[] = 'Chestia'; +$aNames[] = 'Chrispeels'; +$aNames[] = 'Christiaens'; +$aNames[] = 'Christoffel'; +$aNames[] = 'Claes'; +$aNames[] = 'Claessens'; +$aNames[] = 'Claeys'; +$aNames[] = 'Claus'; +$aNames[] = 'Cléban'; +$aNames[] = 'Clébant'; +$aNames[] = 'Clerx'; +$aNames[] = 'Colinus'; +$aNames[] = 'Collard'; +$aNames[] = 'Colleye'; +$aNames[] = 'Collignon'; +$aNames[] = 'Collin'; +$aNames[] = 'Colson'; +$aNames[] = 'Cool'; +$aNames[] = 'Cools'; +$aNames[] = 'Coppens'; +$aNames[] = 'Corain'; +$aNames[] = 'Corijn'; +$aNames[] = 'Corin'; +$aNames[] = 'Cornelis'; +$aNames[] = 'Cornet'; +$aNames[] = 'Corrin'; +$aNames[] = 'Corring'; +$aNames[] = 'Corringer'; +$aNames[] = 'Coryn'; +$aNames[] = 'Coudyser'; +$aNames[] = 'Couhysder'; +$aNames[] = 'Coutijser'; +$aNames[] = 'Coutiser'; +$aNames[] = 'Crab'; +$aNames[] = 'Crabbe'; +$aNames[] = 'Crama'; +$aNames[] = 'Crépez'; +$aNames[] = 'Crespel'; +$aNames[] = 'Crevisse'; +$aNames[] = 'Crevits'; +$aNames[] = 'Crispeel'; +$aNames[] = 'Crispeels'; +$aNames[] = 'Crispel'; +$aNames[] = 'Crispiels'; +$aNames[] = 'Cuvelier'; +$aNames[] = 'Cuypers'; +$aNames[] = 'Daan'; +$aNames[] = 'Daels'; +$aNames[] = 'Daems'; +$aNames[] = 'Dalmans'; +$aNames[] = 'Damard'; +$aNames[] = 'Damart'; +$aNames[] = 'Danis'; +$aNames[] = 'Dany'; +$aNames[] = 'Danys'; +$aNames[] = 'Dapvril'; +$aNames[] = 'Daufresne'; +$aNames[] = 'Dawance'; +$aNames[] = 'Debacker'; +$aNames[] = 'Debaere'; +$aNames[] = 'Debakker'; +$aNames[] = 'Debaut'; +$aNames[] = 'Debecker'; +$aNames[] = 'Debekker'; +$aNames[] = 'Debled'; +$aNames[] = 'Deboschere'; +$aNames[] = 'Deboscker'; +$aNames[] = 'Deboskre'; +$aNames[] = 'Debosscher'; +$aNames[] = 'Debosschere'; +$aNames[] = 'Debusschere'; +$aNames[] = 'Debuyst'; +$aNames[] = 'Declerck'; +$aNames[] = 'Declercq'; +$aNames[] = 'Decock'; +$aNames[] = 'Decocq'; +$aNames[] = 'Decrucq'; +$aNames[] = 'Decruyenaere'; +$aNames[] = 'Defaux'; +$aNames[] = 'Defawe'; +$aNames[] = 'Degroote'; +$aNames[] = 'Dehoorne'; +$aNames[] = 'Dehorne'; +$aNames[] = 'Dehornes'; +$aNames[] = 'Deilgat'; +$aNames[] = 'Dejong'; +$aNames[] = 'Dejonghe'; +$aNames[] = 'Dekale'; +$aNames[] = 'Dekimpe'; +$aNames[] = 'Dekoch'; +$aNames[] = 'Dekuiper'; +$aNames[] = 'Dekyndt'; +$aNames[] = 'Delacuvellerie'; +$aNames[] = 'Delafosse'; +$aNames[] = 'Delahaye'; +$aNames[] = 'Delahayes'; +$aNames[] = 'Delbouille'; +$aNames[] = 'Delboulle'; +$aNames[] = 'Delcorps'; +$aNames[] = 'Delflache'; +$aNames[] = 'Delfosse'; +$aNames[] = 'Delgat'; +$aNames[] = 'Delhaye'; +$aNames[] = 'Delhoste'; +$aNames[] = 'Delhotte'; +$aNames[] = 'Delmare'; +$aNames[] = 'Delmer'; +$aNames[] = 'Delobbe'; +$aNames[] = 'Delobe'; +$aNames[] = 'Delobes'; +$aNames[] = 'Delplace'; +$aNames[] = 'Delvaux'; +$aNames[] = 'Demain'; +$aNames[] = 'Demeiere'; +$aNames[] = 'Demeyer'; +$aNames[] = 'Demoor'; +$aNames[] = 'Demoore'; +$aNames[] = 'Demunck'; +$aNames[] = 'Demuynck'; +$aNames[] = 'Den'; +$aNames[] = 'Denaeyer'; +$aNames[] = 'Denayer'; +$aNames[] = 'Deneyer'; +$aNames[] = 'Denis'; +$aNames[] = 'Denoor'; +$aNames[] = 'Depannemaecker'; +$aNames[] = 'Depelsemacker'; +$aNames[] = 'Depelsemaeker'; +$aNames[] = 'Depelsenaire'; +$aNames[] = 'Depelseneer'; +$aNames[] = 'Depercenaire'; +$aNames[] = 'Depester'; +$aNames[] = 'Depiéreux'; +$aNames[] = 'Depierreux'; +$aNames[] = 'Depireux'; +$aNames[] = 'Depoorter'; +$aNames[] = 'Depoortere'; +$aNames[] = 'Depooter'; +$aNames[] = 'Depootere'; +$aNames[] = 'Deporter'; +$aNames[] = 'Deportere'; +$aNames[] = 'Depoterre'; +$aNames[] = 'Deprez'; +$aNames[] = 'Deramaix'; +$aNames[] = 'Deroosse'; +$aNames[] = 'Desandrouins'; +$aNames[] = 'Descamps'; +$aNames[] = 'Deschepper'; +$aNames[] = 'Desmedt'; +$aNames[] = 'Desmet'; +$aNames[] = 'Desmets'; +$aNames[] = 'Desmeytere'; +$aNames[] = 'Desmidt'; +$aNames[] = 'Desmidts'; +$aNames[] = 'Desmit'; +$aNames[] = 'Desmyter'; +$aNames[] = 'Desmytter'; +$aNames[] = 'Desmyttere'; +$aNames[] = 'Després'; +$aNames[] = 'Despret'; +$aNames[] = 'Desprets'; +$aNames[] = 'Despretz'; +$aNames[] = 'Desprey'; +$aNames[] = 'Desprez'; +$aNames[] = 'Destoute'; +$aNames[] = 'Deswart'; +$aNames[] = 'Deswarte'; +$aNames[] = 'Dethier'; +$aNames[] = 'Deur'; +$aNames[] = 'Deurwaerder'; +$aNames[] = 'Devis'; +$aNames[] = 'Devloo'; +$aNames[] = 'Devos'; +$aNames[] = 'Devriend'; +$aNames[] = 'Dewever'; +$aNames[] = 'Dewit'; +$aNames[] = 'Dewitte'; +$aNames[] = 'Dewyse'; +$aNames[] = 'Dhaeyer'; +$aNames[] = "D'Haeyer"; +$aNames[] = 'Dhoeraen'; +$aNames[] = "D'Hoeraen"; +$aNames[] = "D'Hoolaege"; +$aNames[] = 'Dierckx'; +$aNames[] = 'Dierik'; +$aNames[] = 'Doeraene'; +$aNames[] = 'Dolhaeghe'; +$aNames[] = 'Domiens'; +$aNames[] = 'Dominicus'; +$aNames[] = 'Dondaine'; +$aNames[] = 'Dondeine'; +$aNames[] = 'Dondenne'; +$aNames[] = 'Dondeyne'; +$aNames[] = 'Doolaeghe'; +$aNames[] = 'Doolaegue'; +$aNames[] = 'Doolage'; +$aNames[] = 'Doorn'; +$aNames[] = 'Doorne'; +$aNames[] = 'Doorneman'; +$aNames[] = 'Draier'; +$aNames[] = 'Dresselaers'; +$aNames[] = 'Dubled'; +$aNames[] = 'Dubois'; +$aNames[] = 'Dumont'; +$aNames[] = 'Dupont'; +$aNames[] = 'Duquesnay'; +$aNames[] = 'Duquesne'; +$aNames[] = 'Duquesnoy'; +$aNames[] = 'Ebrard'; +$aNames[] = 'Eeckeman'; +$aNames[] = 'Eerkens'; +$aNames[] = 'Erckens'; +$aNames[] = 'Erk'; +$aNames[] = 'Erken'; +$aNames[] = 'Erkens'; +$aNames[] = 'Etienne'; +$aNames[] = 'Euvrard'; +$aNames[] = 'Evert'; +$aNames[] = 'Evrard'; +$aNames[] = 'Evras'; +$aNames[] = 'Evrat'; +$aNames[] = 'Eyck'; +$aNames[] = 'Eysermans'; +$aNames[] = 'Fawat'; +$aNames[] = 'Faweux'; +$aNames[] = 'Fee'; +$aNames[] = 'Felix'; +$aNames[] = 'Flamenck'; +$aNames[] = 'Floche'; +$aNames[] = 'Floquet'; +$aNames[] = 'Fontaine'; +$aNames[] = 'Fonteyne'; +$aNames[] = 'Fraigany'; +$aNames[] = 'Fraigneux'; +$aNames[] = 'Francoeur'; +$aNames[] = 'François'; +$aNames[] = 'Francon'; +$aNames[] = 'Frankel'; +$aNames[] = 'Franken'; +$aNames[] = 'Frankeur'; +$aNames[] = 'Frans'; +$aNames[] = 'Fransman'; +$aNames[] = 'Fransolet'; +$aNames[] = 'Franzman'; +$aNames[] = 'Frijer'; +$aNames[] = 'Gabriels'; +$aNames[] = 'Gadisseur'; +$aNames[] = 'Gadisseux'; +$aNames[] = 'Gasthuys'; +$aNames[] = 'Gaudisseu'; +$aNames[] = 'Geeregat'; +$aNames[] = 'Geerts'; +$aNames[] = 'Geerts'; +$aNames[] = 'Geets'; +$aNames[] = 'Gehucht'; +$aNames[] = 'Geiregat'; +$aNames[] = 'Gendebien'; +$aNames[] = 'Genot'; +$aNames[] = 'Georges'; +$aNames[] = 'Gérard'; +$aNames[] = 'Gerlache'; +$aNames[] = 'Gerlaxhe'; +$aNames[] = 'Germay'; +$aNames[] = 'Germéa'; +$aNames[] = 'Germeau'; +$aNames[] = 'Ghiste'; +$aNames[] = 'Gidts'; +$aNames[] = 'Giets'; +$aNames[] = 'Gilles'; +$aNames[] = 'Gillet'; +$aNames[] = 'Gilson'; +$aNames[] = 'Gits'; +$aNames[] = 'Glaze'; +$aNames[] = 'Glazeman'; +$aNames[] = 'Goethals'; +$aNames[] = 'Goffin'; +$aNames[] = 'Gomaert'; +$aNames[] = 'Gomardt'; +$aNames[] = 'Goor'; +$aNames[] = 'Goossens'; +$aNames[] = 'Goud'; +$aNames[] = 'Goudman'; +$aNames[] = 'Goudsmith'; +$aNames[] = 'Gourdet'; +$aNames[] = 'Gousson'; +$aNames[] = 'Graas'; +$aNames[] = 'Greggs'; +$aNames[] = 'Gregh'; +$aNames[] = 'Grégoire'; +$aNames[] = 'Gregoor'; +$aNames[] = 'Grewis'; +$aNames[] = 'Groot'; +$aNames[] = 'Groote'; +$aNames[] = 'Grotaers'; +$aNames[] = 'Guillaume'; +$aNames[] = 'Guyaux'; +$aNames[] = 'Haesen'; +$aNames[] = 'Haesevoets'; +$aNames[] = 'Halasi'; +$aNames[] = 'Halazy'; +$aNames[] = 'Hamers'; +$aNames[] = 'Hanssens'; +$aNames[] = 'Hardas'; +$aNames[] = 'Hardat'; +$aNames[] = 'Hardy'; +$aNames[] = 'Heerbrant'; +$aNames[] = 'Hendrick'; +$aNames[] = 'Hendrickx'; +$aNames[] = 'Hendriks'; +$aNames[] = 'Henry'; +$aNames[] = 'Herbrand'; +$aNames[] = 'Herbrandt'; +$aNames[] = 'Herbrant'; +$aNames[] = 'Herman'; +$aNames[] = 'Hermann'; +$aNames[] = 'Hermans'; +$aNames[] = 'Herten'; +$aNames[] = 'Hertogs'; +$aNames[] = 'Hertogue'; +$aNames[] = 'Heylen'; +$aNames[] = 'Heymans'; +$aNames[] = 'Heynemans'; +$aNames[] = 'Heyrman'; +$aNames[] = 'Hinck'; +$aNames[] = 'Hinckel'; +$aNames[] = 'Hincker'; +$aNames[] = 'Hinkel'; +$aNames[] = 'Hinkels'; +$aNames[] = 'Hinkens'; +$aNames[] = 'Hinker'; +$aNames[] = 'Hinkle'; +$aNames[] = 'Hoefnagel'; +$aNames[] = 'Hoefnagels'; +$aNames[] = 'Holemans'; +$aNames[] = 'Honnay'; +$aNames[] = 'Horlin'; +$aNames[] = 'Houvenaghel'; +$aNames[] = 'Hoyois'; +$aNames[] = 'Hubert'; +$aNames[] = 'Huig'; +$aNames[] = 'Ickx'; +$aNames[] = 'Istace'; +$aNames[] = 'Istasse'; +$aNames[] = 'Jaak'; +$aNames[] = 'Jaap'; +$aNames[] = 'Jacob'; +$aNames[] = 'Jacobs'; +$aNames[] = 'Jacques'; +$aNames[] = 'Jacquet'; +$aNames[] = 'Jan'; +$aNames[] = 'Janhes'; +$aNames[] = 'Jansen'; +$aNames[] = 'Janssen'; +$aNames[] = 'Janssens'; +$aNames[] = 'Jef'; +$aNames[] = 'Jenot'; +$aNames[] = 'Jeuniaux'; +$aNames[] = 'Joire'; +$aNames[] = 'Jone'; +$aNames[] = 'Joneau'; +$aNames[] = 'Jonet'; +$aNames[] = 'Jonet'; +$aNames[] = 'Jongers'; +$aNames[] = 'Jonné'; +$aNames[] = 'Jonnet'; +$aNames[] = 'Jordaens'; +$aNames[] = 'Jorez'; +$aNames[] = 'Joris'; +$aNames[] = 'Jorissen'; +$aNames[] = 'Jozef'; +$aNames[] = 'Julianus'; +$aNames[] = 'Julius'; +$aNames[] = 'Jurgen'; +$aNames[] = 'Kaalman'; +$aNames[] = 'Kaisin'; +$aNames[] = 'Keetels'; +$aNames[] = 'Kenens'; +$aNames[] = 'Kenes'; +$aNames[] = 'Kenis'; +$aNames[] = 'Kennens'; +$aNames[] = 'Kennes'; +$aNames[] = 'Kennis'; +$aNames[] = 'Kesteloot'; +$aNames[] = 'Ketel'; +$aNames[] = 'Ketelsmit'; +$aNames[] = 'Kiecken'; +$aNames[] = 'Kimpe'; +$aNames[] = 'Kinnen'; +$aNames[] = 'Klein'; +$aNames[] = 'Kleineman'; +$aNames[] = 'Kleiner'; +$aNames[] = 'Kleinerman'; +$aNames[] = 'Kleinman'; +$aNames[] = 'Klerk'; +$aNames[] = 'Kleynen'; +$aNames[] = 'Klingeleers'; +$aNames[] = 'Kobus'; +$aNames[] = 'Koeck'; +$aNames[] = 'Konninckx'; +$aNames[] = 'Koolman'; +$aNames[] = 'Korring'; +$aNames[] = 'Kramers'; +$aNames[] = 'Kreemers'; +$aNames[] = 'Kuipers'; +$aNames[] = 'Labbez'; +$aNames[] = 'Lacroix'; +$aNames[] = 'Laenen'; +$aNames[] = 'Laenens'; +$aNames[] = 'Lafontaine'; +$aNames[] = 'Lambert'; +$aNames[] = 'Lambrechts'; +$aNames[] = 'Lanen'; +$aNames[] = 'Lanens'; +$aNames[] = 'Langlez'; +$aNames[] = 'Lapayre'; +$aNames[] = 'Laseur'; +$aNames[] = 'Laseure'; +$aNames[] = 'Lauffer'; +$aNames[] = 'Laurent'; +$aNames[] = 'Lauwers'; +$aNames[] = 'Le Demunck'; +$aNames[] = 'Leboutte'; +$aNames[] = 'Lebrun'; +$aNames[] = 'Leclerc'; +$aNames[] = 'Leclercq'; +$aNames[] = 'Lecocq'; +$aNames[] = 'Lecomte'; +$aNames[] = 'Ledecq'; +$aNames[] = 'Leenhard'; +$aNames[] = 'Leenhart'; +$aNames[] = 'Lefebvre'; +$aNames[] = 'Lefèvre'; +$aNames[] = 'Legrand'; +$aNames[] = 'Lejeune'; +$aNames[] = 'Lemaire'; +$aNames[] = 'Lemmens'; +$aNames[] = 'Lemonnier'; +$aNames[] = 'Lemounie'; +$aNames[] = 'Lenaerts'; +$aNames[] = 'Lénel'; +$aNames[] = 'Lénelle'; +$aNames[] = 'Lennel'; +$aNames[] = 'Léonard'; +$aNames[] = 'Lepoutre'; +$aNames[] = 'Leprette'; +$aNames[] = 'Lepropre'; +$aNames[] = 'Leroy'; +$aNames[] = 'Lescohy'; +$aNames[] = 'Lesoil'; +$aNames[] = 'Lesoile'; +$aNames[] = 'Lesoille'; +$aNames[] = 'Levecq'; +$aNames[] = 'Lewek'; +$aNames[] = 'Libert'; +$aNames[] = 'Liens'; +$aNames[] = 'Liephoudt'; +$aNames[] = 'Liepot'; +$aNames[] = 'Liepout'; +$aNames[] = 'Lieseborghs'; +$aNames[] = 'Liesenborghs'; +$aNames[] = 'Lietaer'; +$aNames[] = 'Lietaert'; +$aNames[] = 'Lietar'; +$aNames[] = 'Liétar'; +$aNames[] = 'Liétard'; +$aNames[] = 'Liétart'; +$aNames[] = 'Lievens'; +$aNames[] = 'Lievesoons'; +$aNames[] = 'Lievevrouw'; +$aNames[] = 'Lievrouw'; +$aNames[] = 'Liévrouw'; +$aNames[] = 'Lievrow'; +$aNames[] = 'Linglay'; +$aNames[] = 'Linglet'; +$aNames[] = 'Liphout'; +$aNames[] = 'Lisenborgh'; +$aNames[] = 'Lisenborgs'; +$aNames[] = 'Locreille'; +$aNames[] = 'Locrel'; +$aNames[] = 'Locrelle'; +$aNames[] = 'Lode'; +$aNames[] = 'Loo'; +$aNames[] = 'Lorfèvre'; +$aNames[] = 'Lorphêvre'; +$aNames[] = 'Losseau'; +$aNames[] = 'Losset'; +$aNames[] = 'Louis'; +$aNames[] = 'Louzeau'; +$aNames[] = 'Lowie'; +$aNames[] = 'Ludovicus'; +$aNames[] = 'Lugen'; +$aNames[] = 'Lugens'; +$aNames[] = 'Lust'; +$aNames[] = 'Lustig'; +$aNames[] = 'Luyer'; +$aNames[] = 'Luyrik'; +$aNames[] = 'Luyten'; +$aNames[] = 'Lyphoudt'; +$aNames[] = 'Lyphout'; +$aNames[] = 'Maca'; +$aNames[] = 'Maertens'; +$aNames[] = 'Maes'; +$aNames[] = 'Maessen'; +$aNames[] = 'Mahieu'; +$aNames[] = 'Maka'; +$aNames[] = 'Malchamp'; +$aNames[] = 'Malchamps'; +$aNames[] = 'Malmedier'; +$aNames[] = 'Malmedy'; +$aNames[] = 'Malmendier'; +$aNames[] = 'Mangon'; +$aNames[] = 'Maqua'; +$aNames[] = 'Marchal'; +$aNames[] = 'Marckx'; +$aNames[] = 'Marcus'; +$aNames[] = 'Mardaga'; +$aNames[] = 'Maréchal'; +$aNames[] = 'Maria'; +$aNames[] = 'Mark'; +$aNames[] = 'Markgraff'; +$aNames[] = 'Martens'; +$aNames[] = 'Martin'; +$aNames[] = 'Martins'; +$aNames[] = 'Massart'; +$aNames[] = 'Masson'; +$aNames[] = 'Mathieu'; +$aNames[] = 'Mathissen'; +$aNames[] = 'Mathy'; +$aNames[] = 'Matthys'; +$aNames[] = 'Mauchamp'; +$aNames[] = 'Mauchamps'; +$aNames[] = 'Maurichon'; +$aNames[] = 'Maurissen'; +$aNames[] = 'Maurits'; +$aNames[] = 'Mayeur'; +$aNames[] = 'Mayeux'; +$aNames[] = 'Mechelaere'; +$aNames[] = 'Meert'; +$aNames[] = 'Meertens'; +$aNames[] = 'Meester'; +$aNames[] = 'Meeus'; +$aNames[] = 'Melaerts'; +$aNames[] = 'Mellaerts'; +$aNames[] = 'Merchié'; +$aNames[] = 'Merchier'; +$aNames[] = 'Mergeai'; +$aNames[] = 'Mergeay'; +$aNames[] = 'Merjai'; +$aNames[] = 'Merjay'; +$aNames[] = 'Mertens'; +$aNames[] = 'Mertes'; +$aNames[] = 'Merts'; +$aNames[] = 'Mertz'; +$aNames[] = 'Meulemans'; +$aNames[] = 'Meulemeesters'; +$aNames[] = 'Meunier'; +$aNames[] = 'Meurice'; +$aNames[] = 'Mewis'; +$aNames[] = 'Mewissen'; +$aNames[] = 'Michaël'; +$aNames[] = 'Michaux'; +$aNames[] = 'Michel'; +$aNames[] = 'Michiels'; +$aNames[] = 'Mixhel'; +$aNames[] = 'Mochamps'; +$aNames[] = 'Moens'; +$aNames[] = 'Moeyaert'; +$aNames[] = 'Moiling'; +$aNames[] = 'Moinil'; +$aNames[] = 'Molemans'; +$aNames[] = 'Molenaers'; +$aNames[] = 'Monceau'; +$aNames[] = 'Moncia'; +$aNames[] = 'Monciaux'; +$aNames[] = 'Monsay'; +$aNames[] = 'Monteyne'; +$aNames[] = 'Moreau'; +$aNames[] = 'Mouyart'; +$aNames[] = 'Moyaert'; +$aNames[] = 'Mullenders'; +$aNames[] = 'Munck'; +$aNames[] = 'Muynck'; +$aNames[] = 'Nachtegael'; +$aNames[] = 'Nagelmaekers'; +$aNames[] = 'Nagels'; +$aNames[] = 'Natus'; +$aNames[] = 'Neel'; +$aNames[] = 'Neels'; +$aNames[] = 'Neuray'; +$aNames[] = 'Neureau'; +$aNames[] = 'Neuret'; +$aNames[] = 'Neurot'; +$aNames[] = 'Neuts'; +$aNames[] = 'Neuven'; +$aNames[] = 'Neven'; +$aNames[] = 'Nguyen'; +$aNames[] = 'Nicolas'; +$aNames[] = 'Nicolaus'; +$aNames[] = 'Nicolus'; +$aNames[] = 'Nijs'; +$aNames[] = 'Niklaas'; +$aNames[] = 'Noël'; +$aNames[] = 'Nuts'; +$aNames[] = 'Nuttin'; +$aNames[] = 'Ochin'; +$aNames[] = 'Olivier'; +$aNames[] = 'Olyff'; +$aNames[] = 'Paindavaine'; +$aNames[] = 'Pannaye'; +$aNames[] = 'Parmentier'; +$aNames[] = 'Pas'; +$aNames[] = 'Pauss'; +$aNames[] = 'Pauwels'; +$aNames[] = 'Peeters'; +$aNames[] = 'Pelser'; +$aNames[] = 'Pelsmaeker'; +$aNames[] = 'Peschon'; +$aNames[] = 'Peschoniez'; +$aNames[] = 'Pester'; +$aNames[] = 'Petersen'; +$aNames[] = 'Petit'; +$aNames[] = 'Pierre'; +$aNames[] = 'Piet'; +$aNames[] = 'Pieters'; +$aNames[] = 'Pietersen'; +$aNames[] = 'Piette'; +$aNames[] = 'Pirard'; +$aNames[] = 'Piron'; +$aNames[] = 'Pirotte'; +$aNames[] = 'Plaats'; +$aNames[] = 'Poels'; +$aNames[] = 'Poelsmans'; +$aNames[] = 'Poncelet'; +$aNames[] = 'Pools'; +$aNames[] = 'Posson'; +$aNames[] = 'Potstainer'; +$aNames[] = 'Potter'; +$aNames[] = 'Pottiaux'; +$aNames[] = 'Pottié'; +$aNames[] = 'Potty'; +$aNames[] = 'Poyon'; +$aNames[] = 'Praat'; +$aNames[] = 'Premereur'; +$aNames[] = 'Premmereur'; +$aNames[] = 'Prevostel'; +$aNames[] = 'Priesse'; +$aNames[] = 'Prisse'; +$aNames[] = 'Proost'; +$aNames[] = 'Prost'; +$aNames[] = 'Proust'; +$aNames[] = 'Putman'; +$aNames[] = 'Putmans'; +$aNames[] = 'Putmans'; +$aNames[] = 'Puttemans'; +$aNames[] = 'Puttemans'; +$aNames[] = 'Quaisin'; +$aNames[] = 'Quesnay'; +$aNames[] = 'Quesne'; +$aNames[] = 'Quesneau'; +$aNames[] = 'Quesnel'; +$aNames[] = 'Quesney'; +$aNames[] = 'Quesnoy'; +$aNames[] = 'Queval'; +$aNames[] = 'Raes'; +$aNames[] = 'Ramael'; +$aNames[] = 'Raucent'; +$aNames[] = 'Rauscent'; +$aNames[] = 'Rausin'; +$aNames[] = 'Raussain'; +$aNames[] = 'Raussent'; +$aNames[] = 'Raussin'; +$aNames[] = 'Raveydts'; +$aNames[] = 'Ravignat'; +$aNames[] = 'Remy'; +$aNames[] = 'Renard'; +$aNames[] = 'Retelet'; +$aNames[] = 'Ricaart'; +$aNames[] = 'Ricaert'; +$aNames[] = 'Ricard'; +$aNames[] = 'Robaert'; +$aNames[] = 'Robbert'; +$aNames[] = 'Robert'; +$aNames[] = 'Roels'; +$aNames[] = 'Roland'; +$aNames[] = 'Rooseels'; +$aNames[] = 'Roosengardt'; +$aNames[] = 'Rosseel'; +$aNames[] = 'Rousseau'; +$aNames[] = 'Saintmaux'; +$aNames[] = 'Saint-Maux'; +$aNames[] = 'Sanctorum'; +$aNames[] = 'Santilman'; +$aNames[] = 'Schmitz'; +$aNames[] = 'Schnock'; +$aNames[] = 'Schoenmakers'; +$aNames[] = 'Schoenman'; +$aNames[] = 'Schoone'; +$aNames[] = 'Scorier'; +$aNames[] = 'Scuvie'; +$aNames[] = 'Scuvie'; +$aNames[] = 'Segers'; +$aNames[] = 'Seghers'; +$aNames[] = 'Seppen'; +$aNames[] = 'Servais'; +$aNames[] = 'Shoen'; +$aNames[] = 'Sijmen'; +$aNames[] = 'Simoens'; +$aNames[] = 'Simon'; +$aNames[] = 'Simons'; +$aNames[] = 'Sinnesaël'; +$aNames[] = 'Sinnesal'; +$aNames[] = 'Slagmolder'; +$aNames[] = 'Slagmulder'; +$aNames[] = 'Slamulder'; +$aNames[] = 'Smal'; +$aNames[] = 'Smeets'; +$aNames[] = 'Smet'; +$aNames[] = 'Smets'; +$aNames[] = 'Smit'; +$aNames[] = 'Smolders'; +$aNames[] = 'Smulders'; +$aNames[] = 'Somers'; +$aNames[] = 'Sottiaux'; +$aNames[] = 'Spinette'; +$aNames[] = 'Sprecher'; +$aNames[] = 'Stas'; +$aNames[] = 'Stass'; +$aNames[] = 'Stassaert'; +$aNames[] = 'Stassar'; +$aNames[] = 'Stassard'; +$aNames[] = 'Stassart'; +$aNames[] = 'Stasse'; +$aNames[] = 'Stassiaux'; +$aNames[] = 'Stassin'; +$aNames[] = 'Stassinet'; +$aNames[] = 'Statius'; +$aNames[] = 'Steculorum'; +$aNames[] = 'Stefaans'; +$aNames[] = 'Stercken'; +$aNames[] = 'Sterckmans'; +$aNames[] = 'Sterckx'; +$aNames[] = 'Stevens'; +$aNames[] = 'Stier'; +$aNames[] = 'Stiers'; +$aNames[] = 'Stievens'; +$aNames[] = 'Stine'; +$aNames[] = 'Stoffel'; +$aNames[] = 'Stordair'; +$aNames[] = 'Stordeur'; +$aNames[] = 'Stoutmans'; +$aNames[] = 'Swart'; +$aNames[] = 'Swarte'; +$aNames[] = 'Tack'; +$aNames[] = 'Taverner'; +$aNames[] = 'Teissant'; +$aNames[] = 'Terreur'; +$aNames[] = 'Thijs'; +$aNames[] = 'Thiry'; +$aNames[] = 'Thissen'; +$aNames[] = 'Thomas'; +$aNames[] = 'Thonnisen'; +$aNames[] = 'Thuiliau'; +$aNames[] = 'Thuiliaux'; +$aNames[] = 'Thuiliet'; +$aNames[] = 'Thys'; +$aNames[] = 'Tibaut'; +$aNames[] = 'Timmerman'; +$aNames[] = 'Timmermans'; +$aNames[] = 'Tjampens'; +$aNames[] = "T'Jampens"; +$aNames[] = 'Toussaint'; +$aNames[] = 'Trausch'; +$aNames[] = 'Tuiliau'; +$aNames[] = 'Tuiliaux'; +$aNames[] = 'Tuilliet'; +$aNames[] = 'Tuin'; +$aNames[] = 'Tumson'; +$aNames[] = 'Tweelinckx'; +$aNames[] = 'Urbain'; +$aNames[] = 'Urting'; +$aNames[] = 'Vanbattel'; +$aNames[] = 'Vanbergh'; +$aNames[] = 'Vandamme'; +$aNames[] = 'Vandenberghe'; +$aNames[] = 'Vandenbossche'; +$aNames[] = 'Vandenbussche'; +$aNames[] = 'Vandendorpe'; +$aNames[] = 'Vandeputte'; +$aNames[] = 'Vanderhorst'; +$aNames[] = 'Vanderlinden'; +$aNames[] = 'Vanderplaetsen'; +$aNames[] = 'Vandevelde'; +$aNames[] = 'Vandoolaeghe'; +$aNames[] = 'Vandorpe'; +$aNames[] = 'Vanlierde'; +$aNames[] = 'Vanpé'; +$aNames[] = 'Vanpede'; +$aNames[] = 'Vanpée'; +$aNames[] = 'Vansteertegem'; +$aNames[] = 'Vecq'; +$aNames[] = 'Veld'; +$aNames[] = 'Veldmann'; +$aNames[] = 'Vellemans'; +$aNames[] = 'Veraghe'; +$aNames[] = 'Veraghen'; +$aNames[] = 'Verbeeck'; +$aNames[] = 'Verbeke'; +$aNames[] = 'Verbruggen'; +$aNames[] = 'Vercammen'; +$aNames[] = 'Vercheval'; +$aNames[] = 'Verdoolaeg(H)E'; +$aNames[] = 'Verhaege'; +$aNames[] = 'Verhaegen'; +$aNames[] = 'Verhaeghe'; +$aNames[] = 'Verhaeghen'; +$aNames[] = 'Verhaegue'; +$aNames[] = 'Verhage'; +$aNames[] = 'Verhagen'; +$aNames[] = 'Verhaghe'; +$aNames[] = 'Verhelst'; +$aNames[] = 'Verheyen'; +$aNames[] = 'Verhoeven'; +$aNames[] = 'Verlinden'; +$aNames[] = 'Vermeer'; +$aNames[] = 'Vermeersch'; +$aNames[] = 'Vermeiren'; +$aNames[] = 'Vermeren'; +$aNames[] = 'Vermeulen'; +$aNames[] = 'Vermotte'; +$aNames[] = 'Verplaetse'; +$aNames[] = 'Verplancke'; +$aNames[] = 'Verplancken'; +$aNames[] = 'Verschueren'; +$aNames[] = 'Verslijke'; +$aNames[] = 'Verslycke'; +$aNames[] = 'Verstraete'; +$aNames[] = 'Verstraeten'; +$aNames[] = 'Vervoort'; +$aNames[] = 'Vet'; +$aNames[] = 'Vette'; +$aNames[] = 'Viatour'; +$aNames[] = 'Vieutems'; +$aNames[] = 'Vieuxtemps'; +$aNames[] = 'Vilain'; +$aNames[] = 'Vincent'; +$aNames[] = 'Vinchent'; +$aNames[] = 'Visje'; +$aNames[] = 'Vlaamsche'; +$aNames[] = 'Vlaeminck'; +$aNames[] = 'Vlaemynck'; +$aNames[] = 'Vlaminck'; +$aNames[] = 'Vlamynck'; +$aNames[] = 'Vlemincks'; +$aNames[] = 'Vleminckx'; +$aNames[] = 'Vleminx'; +$aNames[] = 'Vlemynckx'; +$aNames[] = 'Vogels'; +$aNames[] = 'Volckaert'; +$aNames[] = 'Volkaert'; +$aNames[] = 'Volkaerts'; +$aNames[] = 'Volkart'; +$aNames[] = 'Volkert'; +$aNames[] = 'Voller'; +$aNames[] = 'Vos'; +$aNames[] = 'Vossen'; +$aNames[] = 'Vrank'; +$aNames[] = 'Vrindt'; +$aNames[] = 'Vrolijt'; +$aNames[] = 'Vrolyck'; +$aNames[] = 'Vullers'; +$aNames[] = 'Wagemans'; +$aNames[] = 'Wagenmann'; +$aNames[] = 'Waghon'; +$aNames[] = 'Wagon'; +$aNames[] = 'Walle'; +$aNames[] = 'Wastiaux'; +$aNames[] = 'Watrigant'; +$aNames[] = 'Watriquant'; +$aNames[] = 'Watteau'; +$aNames[] = 'Watteau'; +$aNames[] = 'Watteaux'; +$aNames[] = 'Watteaux'; +$aNames[] = 'Wattecamp'; +$aNames[] = 'Wattecamps'; +$aNames[] = 'Wattecant'; +$aNames[] = 'Watteel'; +$aNames[] = 'Wattel'; +$aNames[] = 'Wattelle'; +$aNames[] = 'Wattiau'; +$aNames[] = 'Wattiaux'; +$aNames[] = 'Wattieaux'; +$aNames[] = 'Wauters'; +$aNames[] = 'Weers'; +$aNames[] = 'Weerts'; +$aNames[] = 'Wek'; +$aNames[] = 'Wevers'; +$aNames[] = 'Weynen'; +$aNames[] = 'Wilbaert'; +$aNames[] = 'Wilfart'; +$aNames[] = 'Willems'; +$aNames[] = 'Willock'; +$aNames[] = 'Willocq'; +$aNames[] = 'Wilock'; +$aNames[] = 'Wintgens'; +$aNames[] = 'Wouter'; +$aNames[] = 'Wouters'; +$aNames[] = 'Wuyts'; +$aNames[] = 'Wylock'; +$aNames[] = 'Wylocke'; +$aNames[] = 'Yildirim'; +$aNames[] = 'Yilmaz'; +$aNames[] = 'Zadelaar'; +$aNames[] = 'Zegers'; +$aNames[] = 'Zeggers'; +$aNames[] = 'Zègres'; +$aNames[] = 'Bernard'; +$aNames[] = 'Bertrand'; +$aNames[] = 'Blanc'; +$aNames[] = 'Bonnet'; +$aNames[] = 'David'; +$aNames[] = 'Dubois'; +$aNames[] = 'Durand'; +$aNames[] = 'Fournier'; +$aNames[] = 'Garcia'; +$aNames[] = 'Girard'; +$aNames[] = 'Lambert'; +$aNames[] = 'Laurent'; +$aNames[] = 'Lefebvre'; +$aNames[] = 'Leroy'; +$aNames[] = 'Martin'; +$aNames[] = 'Michel'; +$aNames[] = 'Moreau'; +$aNames[] = 'Morel'; +$aNames[] = 'Petit'; +$aNames[] = 'Rang'; +$aNames[] = 'Richard'; +$aNames[] = 'Robert'; +$aNames[] = 'Rousseau'; +$aNames[] = 'Roux'; +$aNames[] = 'Simon'; +$aNames[] = 'Thomas'; +$aNames[] = 'André'; +$aNames[] = 'Chevalier'; +$aNames[] = 'Clément'; +$aNames[] = 'Dupont'; +$aNames[] = 'Faure'; +$aNames[] = 'François'; +$aNames[] = 'Garnier'; +$aNames[] = 'Gauthier'; +$aNames[] = 'Gautier'; +$aNames[] = 'Guerin'; +$aNames[] = 'Henry'; +$aNames[] = 'Lefèvre'; +$aNames[] = 'Legrand'; +$aNames[] = 'Lopez'; +$aNames[] = 'Martinez'; +$aNames[] = 'Masson'; +$aNames[] = 'Mathieu'; +$aNames[] = 'Mercier'; +$aNames[] = 'Morin'; +$aNames[] = 'Muller'; +$aNames[] = 'Nicolas'; +$aNames[] = 'Perrin'; +$aNames[] = 'Rang'; +$aNames[] = 'Robin'; +$aNames[] = 'Roussel'; +$aNames[] = 'Vincent'; +$aNames[] = 'Arnaud'; +$aNames[] = 'Blanchand'; +$aNames[] = 'Boyer'; +$aNames[] = 'Brun'; +$aNames[] = 'Brunet'; +$aNames[] = 'Denis'; +$aNames[] = 'Dufour'; +$aNames[] = 'Dumont'; +$aNames[] = 'Duval'; +$aNames[] = 'Fabre'; +$aNames[] = 'Fontaine'; +$aNames[] = 'Gaillard'; +$aNames[] = 'Giraud'; +$aNames[] = 'Joly'; +$aNames[] = 'Lemaire'; +$aNames[] = 'Lucas'; +$aNames[] = 'Marchand'; +$aNames[] = 'Meunier'; +$aNames[] = 'Meyer'; +$aNames[] = 'Noël'; +$aNames[] = 'Perez'; +$aNames[] = 'Rang'; +$aNames[] = 'Roche'; +$aNames[] = 'Roy'; +$aNames[] = 'Sanchez'; +$aNames[] = 'Vidal'; +$aNames[] = 'Adamcki'; +$aNames[] = 'Adamczak'; +$aNames[] = 'Adamczewski'; +$aNames[] = 'Adamczyk'; +$aNames[] = 'Adamiak'; +$aNames[] = 'Adamowicz'; +$aNames[] = 'Adamowitz'; +$aNames[] = 'Adamski'; +$aNames[] = 'Adamsky'; +$aNames[] = 'Adamus'; +$aNames[] = 'Ambroziak'; +$aNames[] = 'Ambroziewicz'; +$aNames[] = 'Ambrozy'; +$aNames[] = 'Andrzeg'; +$aNames[] = 'Andrzejak'; +$aNames[] = 'Antczak'; +$aNames[] = 'Antkowiak'; +$aNames[] = 'Augustyniak'; +$aNames[] = 'Balcerzak'; +$aNames[] = 'Balcrowiak'; +$aNames[] = 'Balczarek'; +$aNames[] = 'Banaszak'; +$aNames[] = 'Baranowski'; +$aNames[] = 'Bejm'; +$aNames[] = 'Biczysko'; +$aNames[] = 'Biernaciak'; +$aNames[] = 'Biernacki'; +$aNames[] = 'Biernaczyk'; +$aNames[] = 'Biernat'; +$aNames[] = 'Blaszak'; +$aNames[] = 'Blaszczak'; +$aNames[] = 'Blaszczyk'; +$aNames[] = 'Bloch'; +$aNames[] = 'Bloszak'; +$aNames[] = 'Boguslawiak'; +$aNames[] = 'Bor'; +$aNames[] = 'Brama'; +$aNames[] = 'Bressler'; +$aNames[] = 'Brezisky'; +$aNames[] = 'Brzezinski'; +$aNames[] = 'Buczak'; +$aNames[] = 'Buczek'; +$aNames[] = 'Buczko'; +$aNames[] = 'Buczkowski'; +$aNames[] = 'Buczynski'; +$aNames[] = 'Bugajny'; +$aNames[] = 'Bukowski'; +$aNames[] = 'Bulinski'; +$aNames[] = 'Bulinsky'; +$aNames[] = 'Cepak'; +$aNames[] = 'Cepek'; +$aNames[] = 'Ceremuga'; +$aNames[] = 'Cérémuga'; +$aNames[] = 'Cernota'; +$aNames[] = 'Charbul'; +$aNames[] = 'Chlebowski'; +$aNames[] = 'Chmiel'; +$aNames[] = 'Chodkowski'; +$aNames[] = 'Ciemior'; +$aNames[] = 'Ciepluch'; +$aNames[] = 'Cieplucha'; +$aNames[] = 'Ciesielski'; +$aNames[] = 'Cieslak'; +$aNames[] = 'Cieslik'; +$aNames[] = 'Cyganek'; +$aNames[] = 'Cyganik'; +$aNames[] = 'Cygankiewicz'; +$aNames[] = 'Czajka'; +$aNames[] = 'Czajkowski'; +$aNames[] = 'Czapka'; +$aNames[] = 'Czapski'; +$aNames[] = 'Czeremcha'; +$aNames[] = 'Czeremuga'; +$aNames[] = 'Dabbor'; +$aNames[] = 'Dabik'; +$aNames[] = 'Dabrowski'; +$aNames[] = 'Dambek'; +$aNames[] = 'Dambik'; +$aNames[] = 'Damian'; +$aNames[] = 'Danielak'; +$aNames[] = 'Danielczak'; +$aNames[] = 'Danilevitch'; +$aNames[] = 'Danilewicz'; +$aNames[] = 'Dawidowicz'; +$aNames[] = 'Deka'; +$aNames[] = 'Dembski'; +$aNames[] = 'Dembsky'; +$aNames[] = 'Dobosz'; +$aNames[] = 'Dobosz'; +$aNames[] = 'Dobrowolski'; +$aNames[] = 'Domin'; +$aNames[] = 'Dominiak'; +$aNames[] = 'Dominiczak'; +$aNames[] = 'Dominik'; +$aNames[] = 'Dominikowski'; +$aNames[] = 'Doroszewski'; +$aNames[] = 'Dowbor'; +$aNames[] = 'Dudek'; +$aNames[] = 'Erazmus'; +$aNames[] = 'Feliks'; +$aNames[] = 'Fialek'; +$aNames[] = 'Fijal'; +$aNames[] = 'Fijalek'; +$aNames[] = 'Fijalkowski'; +$aNames[] = 'Filipczak'; +$aNames[] = 'Filipczuk'; +$aNames[] = 'Filipek'; +$aNames[] = 'Filipiak'; +$aNames[] = 'Filipiuk'; +$aNames[] = 'Filipkowski'; +$aNames[] = 'Filipowicz'; +$aNames[] = 'Filipowski'; +$aNames[] = 'Filipski'; +$aNames[] = 'Firlej'; +$aNames[] = 'Florack'; +$aNames[] = 'Florczak'; +$aNames[] = 'Fracczak'; +$aNames[] = 'Frackowiak'; +$aNames[] = 'Franciscek'; +$aNames[] = 'Fratczak'; +$aNames[] = 'Frydryszak'; +$aNames[] = 'Gabryelczyk'; +$aNames[] = 'Gabrysiak'; +$aNames[] = 'Gaik'; +$aNames[] = 'Galinski'; +$aNames[] = 'Galka'; +$aNames[] = 'Gasztowtt'; +$aNames[] = 'Glebocki'; +$aNames[] = 'Glinczanki'; +$aNames[] = 'Glowacki'; +$aNames[] = 'Gniewek'; +$aNames[] = 'Godes'; +$aNames[] = 'Godès'; +$aNames[] = 'Godesh'; +$aNames[] = 'Gomolka'; +$aNames[] = 'Gongal'; +$aNames[] = 'Goszczynski'; +$aNames[] = 'Grabara'; +$aNames[] = 'Grabarczyk'; +$aNames[] = 'Grabarz'; +$aNames[] = 'Grabowski'; +$aNames[] = 'Grajoszek'; +$aNames[] = 'Gregorz'; +$aNames[] = 'Gryczkowiak'; +$aNames[] = 'Grzegorczyk'; +$aNames[] = 'Grzeskowiak'; +$aNames[] = 'Grzybek'; +$aNames[] = 'Grzybowski'; +$aNames[] = 'Habiera'; +$aNames[] = 'Halborn'; +$aNames[] = 'Harbul'; +$aNames[] = 'Heilpern'; +$aNames[] = 'Heilporn'; +$aNames[] = 'Heleniak'; +$aNames[] = 'Heltowni'; +$aNames[] = 'Hercberg'; +$aNames[] = 'Ickowicz'; +$aNames[] = 'Idaszek'; +$aNames[] = 'Idkowiak'; +$aNames[] = 'Iglicki'; +$aNames[] = 'Ignasiak'; +$aNames[] = 'Ignatczak'; +$aNames[] = 'Iszezuk'; +$aNames[] = 'Izydorczyk'; +$aNames[] = 'Jablonowski'; +$aNames[] = 'Jachowicz'; +$aNames[] = 'Jackowiak'; +$aNames[] = 'Jackowska'; +$aNames[] = 'Jackowski'; +$aNames[] = 'Jan'; +$aNames[] = 'Janas'; +$aNames[] = 'Janiak'; +$aNames[] = 'Janicki'; +$aNames[] = 'Janik'; +$aNames[] = 'Jankowiak'; +$aNames[] = 'Jankowski'; +$aNames[] = 'Janow'; +$aNames[] = 'Janowczyk'; +$aNames[] = 'Janowiak'; +$aNames[] = 'Janowicz'; +$aNames[] = 'Janowiec'; +$aNames[] = 'Janowski'; +$aNames[] = 'Janusz'; +$aNames[] = 'Jarosz'; +$aNames[] = 'Jaroszek'; +$aNames[] = 'Jaroszewicz'; +$aNames[] = 'Jaroszewski'; +$aNames[] = 'Jaroszuk'; +$aNames[] = 'Jaroszynski'; +$aNames[] = 'Jasicki'; +$aNames[] = 'Jasinski'; +$aNames[] = 'Jaskowiak'; +$aNames[] = 'Jedlenska'; +$aNames[] = 'Jedruch'; +$aNames[] = 'Jedrych'; +$aNames[] = 'Jedrzej'; +$aNames[] = 'Jedrzejak'; +$aNames[] = 'Jedrzejczak'; +$aNames[] = 'Jedrzejczy'; +$aNames[] = 'Jedrzejczyk'; +$aNames[] = 'Jedrzejewski'; +$aNames[] = 'Jelenski'; +$aNames[] = 'Jerzmanowski'; +$aNames[] = 'Jezierski'; +$aNames[] = 'Jodiowski'; +$aNames[] = 'Joskowiak'; +$aNames[] = 'Jozefiak'; +$aNames[] = 'Jozwiak'; +$aNames[] = 'Julia'; +$aNames[] = 'Juliusz'; +$aNames[] = 'Jura'; +$aNames[] = 'Jurak'; +$aNames[] = 'Juras'; +$aNames[] = 'Jurasz'; +$aNames[] = 'Juraszek'; +$aNames[] = 'Jurczak'; +$aNames[] = 'Jurczuk'; +$aNames[] = 'Jurczyk'; +$aNames[] = 'Jurczynski'; +$aNames[] = 'Jurek'; +$aNames[] = 'Martin'; +$aNames[] = 'Durand'; +$aNames[] = 'Robert'; +$aNames[] = 'Dupont'; +$aNames[] = 'Bernard'; +$aNames[] = 'Dubois'; +$aNames[] = 'Petit'; +$aNames[] = 'Cohen'; +$aNames[] = 'Richard'; +$aNames[] = 'Moreau'; +$aNames[] = 'Thomas'; +$aNames[] = 'Nguyen'; +$aNames[] = 'Simon'; +$aNames[] = 'Laurent'; +$aNames[] = 'Michel'; +$aNames[] = 'Levy'; +$aNames[] = 'Vincent'; +$aNames[] = 'David'; +$aNames[] = 'Bertrand'; +$aNames[] = 'Rousseau'; +$aNames[] = 'Leroy'; +$aNames[] = 'Girard'; +$aNames[] = 'Fournier'; +$aNames[] = 'Roux'; +$aNames[] = 'Andre'; +$aNames[] = 'Garnier'; +$aNames[] = 'Mercier'; +$aNames[] = 'Morin'; +$aNames[] = 'Jean'; +$aNames[] = 'Denis'; +$aNames[] = 'Henry'; +$aNames[] = 'Duval'; +$aNames[] = 'Morel'; +$aNames[] = 'Nicolas'; +$aNames[] = 'Francois'; +$aNames[] = 'Blanc'; +$aNames[] = 'Faure'; +$aNames[] = 'Pierre'; +$aNames[] = 'Garcia'; +$aNames[] = 'Lambert'; +$aNames[] = 'Gautier'; +$aNames[] = 'Lefebvre'; +$aNames[] = 'Meunier'; +$aNames[] = 'Lefevre'; +$aNames[] = 'Perrin'; +$aNames[] = 'Legrand'; +$aNames[] = 'Clement'; +$aNames[] = 'Mathieu'; +$aNames[] = 'Bonnet'; +$aNames[] = 'Chevalier'; +$aNames[] = 'Muller'; +$aNames[] = 'Fontaine'; +$aNames[] = 'Robin'; +$aNames[] = 'Blanchard'; +$aNames[] = 'Perez'; +$aNames[] = 'Guerin'; +$aNames[] = 'Masson'; +$aNames[] = 'Roger'; +$aNames[] = 'Gauthier'; +$aNames[] = 'Dupuis'; +$aNames[] = 'Martinez'; +$aNames[] = 'Leroux'; +$aNames[] = 'Bourgeois'; +$aNames[] = 'Dumont'; +$aNames[] = 'Dupond'; +$aNames[] = 'Paul'; +$aNames[] = 'Louis'; +$aNames[] = 'Dufour'; +$aNames[] = 'Meyer'; +$aNames[] = 'Lacroix'; +$aNames[] = 'Noel'; +$aNames[] = 'Fabre'; +$aNames[] = 'Lopez'; +$aNames[] = 'Gerard'; +$aNames[] = 'Lemaire'; +$aNames[] = 'Roussel'; +$aNames[] = 'Berger'; +$aNames[] = 'Barbier'; +$aNames[] = 'Boyer'; +$aNames[] = 'Brun'; +$aNames[] = 'Vidal'; +$aNames[] = 'Giraud'; +$aNames[] = 'Fernandez'; +$aNames[] = 'Marie'; +$aNames[] = 'Roche'; +$aNames[] = 'Colin'; +$aNames[] = 'Tran'; +$aNames[] = 'Marchand'; +$aNames[] = 'Lemoine'; +$aNames[] = 'Charpentier'; + +$aCountries = array(); +$aCountries[] = 'France'; +$aCountries[] = 'United Kingdom'; +$aCountries[] = 'Germany'; +$aCountries[] = 'United States of America'; +$aCountries[] = 'Canada'; +$aCountries[] = 'Switzerland'; +$aCountries[] = 'Belgium'; +$aCountries[] = 'Poland'; +$aCountries[] = 'Slovakia'; +$aCountries[] = 'Italy'; +$aCountries[] = 'Spain'; +$aCountries[] = 'Bulgaria'; + +$aCities = array(); +$aCities[]="Orvault"; +$aCities[]="Oullins"; +$aCities[]="Oyonnax"; +$aCities[]="Ozoir-la-Ferrière"; +$aCities[]="Palaiseau"; +$aCities[]="Pantin"; +$aCities[]="Paris"; +$aCities[]="Pau"; +$aCities[]="Périgueux"; +$aCities[]="Perpignan"; +$aCities[]="Le Perreux-sur-Marne"; +$aCities[]="Pessac"; +$aCities[]="Le Petit-Quevilly"; +$aCities[]="Pierrefitte-sur-Seine"; +$aCities[]="Plaisir"; +$aCities[]="Le Plessis-Robinson"; +$aCities[]="Poissy"; +$aCities[]="Poitiers"; +$aCities[]="Pontault-Combault"; +$aCities[]="Pontoise"; +$aCities[]="Le Port"; +$aCities[]="La Possession"; +$aCities[]="Puteaux"; +$aCities[]="Le Puy-en-Velay"; +$aCities[]="Quimper"; +$aCities[]="Rambouillet"; +$aCities[]="Reims"; +$aCities[]="Rennes"; +$aCities[]="Rezé"; +$aCities[]="Rillieux-la-Pape"; +$aCities[]="Ris-Orangis"; +$aCities[]="Roanne"; +$aCities[]="Rochefort"; +$aCities[]="La Rochelle"; +$aCities[]="La Roche-sur-Yon"; +$aCities[]="Rodez"; +$aCities[]="Romainville"; +$aCities[]="Romans-sur-Isère"; +$aCities[]="Rosny-sous-Bois"; +$aCities[]="Roubaix"; +$aCities[]="Rouen"; +$aCities[]="Rueil-Malmaison"; +$aCities[]="Saint-André"; +$aCities[]="Saint-Benoît"; +$aCities[]="Saint-Brieuc"; +$aCities[]="Saint-Chamond"; +$aCities[]="Saint-Cloud"; +$aCities[]="Saint-Denis"; +$aCities[]="Saint-Denis"; +$aCities[]="Saint-Dié-des-Vosges"; +$aCities[]="Saint-Dizier"; +$aCities[]="Sainte-Foy-lès-Lyon"; +$aCities[]="Sainte-Geneviève-des-Bois"; +$aCities[]="Saintes"; +$aCities[]="Saint-Étienne"; +$aCities[]="Saint-Étienne-du-Rouvray"; +$aCities[]="Saint-Germain-en-Laye"; +$aCities[]="Saint-Herblain"; +$aCities[]="Saint-Joseph"; +$aCities[]="Saint-Laurent-du-Var"; +$aCities[]="Saint-Leu"; +$aCities[]="Saint-Lô"; +$aCities[]="Saint-Louis"; +$aCities[]="Saint-Louis"; +$aCities[]="Saint-Malo"; +$aCities[]="Saint-Martin-d'Hères"; +$aCities[]="Saint-Maur-des-Fossés"; +$aCities[]="Saint-Médard-en-Jalles"; +$aCities[]="Saint-Michel-sur-Orge"; +$aCities[]="Saint-Nazaire"; +$aCities[]="Saint-Ouen"; +$aCities[]="Saint-Paul"; +$aCities[]="Saint-Pierre"; +$aCities[]="Saint-Pol-sur-Mer"; +$aCities[]="Saint-Priest"; +$aCities[]="Saint-Quentin"; +$aCities[]="Saint-Raphaël"; +$aCities[]="Saint-Sébastien-sur-Loire"; +$aCities[]="Salon-de-Provence"; +$aCities[]="Sannois"; +$aCities[]="Sarcelles"; +$aCities[]="Sarreguemines"; +$aCities[]="Sartrouville"; +$aCities[]="Saumur"; +$aCities[]="Savigny-le-Temple"; +$aCities[]="Savigny-sur-Orge"; +$aCities[]="Schiltigheim"; +$aCities[]="Sedan"; +$aCities[]="Sens"; +$aCities[]="Sète"; +$aCities[]="Sevran"; +$aCities[]="Sèvres"; +$aCities[]="La Seyne-sur-Mer"; +$aCities[]="Six-Fours-les-Plages"; +$aCities[]="Soissons"; +$aCities[]="Sotteville-lès-Rouen"; +$aCities[]="Stains"; +$aCities[]="Strasbourg"; +$aCities[]="Sucy-en-Brie"; +$aCities[]="Suresnes"; +$aCities[]="Talence"; +$aCities[]="Le Tampon"; +$aCities[]="Tarbes"; +$aCities[]="Taverny"; +$aCities[]="La Teste-de-Buch"; +$aCities[]="Thiais"; +$aCities[]="Thionville"; +$aCities[]="Thonon-les-Bains"; +$aCities[]="Torcy"; +$aCities[]="Toulon"; +$aCities[]="Toulouse"; +$aCities[]="Tourcoing"; +$aCities[]="Tournefeuille"; +$aCities[]="Tours"; +$aCities[]="Trappes"; +$aCities[]="Tremblay-en-France"; +$aCities[]="Troyes"; +$aCities[]="Les Ulis"; +$aCities[]="Valence"; +$aCities[]="Valenciennes"; +$aCities[]="La Valette-du-Var"; +$aCities[]="Vallauris"; +$aCities[]="Vandœuvre-lès-Nancy"; +$aCities[]="Vannes"; +$aCities[]="Vanves"; +$aCities[]="Vaulx-en-Velin"; +$aCities[]="Vélizy-Villacoublay"; +$aCities[]="Vénissieux"; +$aCities[]="Verdun"; +$aCities[]="Vernon"; +$aCities[]="Versailles"; +$aCities[]="Vertou"; +$aCities[]="Vichy"; +$aCities[]="Vienne"; +$aCities[]="Vierzon"; +$aCities[]="Vigneux-sur-Seine"; +$aCities[]="Villefranche-sur-Saône"; +$aCities[]="Villejuif"; +$aCities[]="Villemomble"; +$aCities[]="Villenave-d'Ornon"; +$aCities[]="Villeneuve-d'Ascq"; +$aCities[]="Villeneuve-la-Garenne"; +$aCities[]="Villeneuve-Saint-Georges"; +$aCities[]="Villeneuve-sur-Lot"; +$aCities[]="Villeparisis"; +$aCities[]="Villepinte"; +$aCities[]="Villeurbanne"; +$aCities[]="Villiers-le-Bel"; +$aCities[]="Villiers-sur-Marne"; +$aCities[]="Vincennes"; +$aCities[]="Viry-Châtillon"; +$aCities[]="Vitrolles"; +$aCities[]="Vitry-sur-Seine"; +$aCities[]="Voiron"; +$aCities[]="Wattrelos"; +$aCities[]="Yerres"; +$aCities[]="Madrid"; +$aCities[]="Mataró"; +$aCities[]="Málaga"; +$aCities[]="Manzanares"; +$aCities[]="Marbella"; +$aCities[]="Marines"; +$aCities[]="Melilla"; +$aCities[]="Mijas"; +$aCities[]="Móstoles"; +$aCities[]="Murcie"; +$aCities[]="Sabadell"; +$aCities[]="Sagonte"; +$aCities[]="Salamanque"; +$aCities[]="Saint-Sébastien"; +$aCities[]="San Antonio de Benagéber"; +$aCities[]="Sant Boi de Llobregat"; +$aCities[]="Santa Cruz de Tenerife"; +$aCities[]="Santander"; +$aCities[]="Saragosse"; +$aCities[]="Ségovia"; +$aCities[]="Serra"; +$aCities[]="Séville"; +$aCities[]="Sitges"; +$aCities[]="Sóller"; +$aCities[]="Soria"; +$aCities[]="Aberdeen"; +$aCities[]="Aberystwyth"; +$aCities[]="Ashford"; +$aCities[]="Armagh"; +$aCities[]="Amersham"; +$aCities[]="Andover"; +$aCities[]="Arundel"; +$aCities[]="Abingdon"; +$aCities[]="Aylesbury"; +$aCities[]="Ayr"; +$aCities[]="Barrow-in-Furness"; +$aCities[]="Bath"; +$aCities[]="Bangor"; +$aCities[]="Bangor"; +$aCities[]="Belfast"; +$aCities[]="Birmingham"; +$aCities[]="Bournemouth"; +$aCities[]="Bradford"; +$aCities[]="Brighton"; +$aCities[]="Bristol"; +$aCities[]="Barrow-in-Furness"; +$aCities[]="Bath"; +$aCities[]="Bangor"; +$aCities[]="Bangor"; +$aCities[]="Belfast"; +$aCities[]="Birmingham"; +$aCities[]="Bournemouth"; +$aCities[]="Bradford"; +$aCities[]="Brighton"; +$aCities[]="Bristol"; +$aCities[]="Eastbourne"; +$aCities[]="Édimbourg"; +$aCities[]="Ely"; +$aCities[]="Epsom"; +$aCities[]="Eton"; +$aCities[]="Evanton"; +$aCities[]="Exeter"; +$aCities[]="Lancaster"; +$aCities[]="Larne"; +$aCities[]="Leeds"; +$aCities[]="Leicester"; +$aCities[]="Lichfield"; +$aCities[]="Lincoln"; +$aCities[]="Lisburn"; +$aCities[]="Liverpool"; +$aCities[]="Londres"; +$aCities[]="Londonderry"; +$aCities[]="Newcastle-upon-Tyne"; +$aCities[]="Newport"; +$aCities[]="Newry"; +$aCities[]="Norwich"; +$aCities[]="Nottingham"; +$aCities[]="Reading"; +$aCities[]="Ripon"; +$aCities[]="Richmond"; +$aCities[]="Ripley"; +$aCities[]="Rugby"; +$aCities[]="Wakefield"; +$aCities[]="Wells"; +$aCities[]="Westminster"; +$aCities[]="Weymouth"; +$aCities[]="Wick"; +$aCities[]="Wigan"; +$aCities[]="Winchester"; +$aCities[]="Windsor"; +$aCities[]="Wolverhampton"; +$aCities[]="Worcester"; +$aCities[]="Wye"; +$aCities[]="Abbeyville"; +$aCities[]="Abbeyville"; +$aCities[]="Aberdeen"; +$aCities[]="Abilene"; +$aCities[]="Abilene"; +$aCities[]="Acron"; +$aCities[]="Ada"; +$aCities[]="Adelanto"; +$aCities[]="Affton"; +$aCities[]="Agoura Hills"; +$aCities[]="Aitkin"; +$aCities[]="Akron"; +$aCities[]="Alabaster"; +$aCities[]="Alameda"; +$aCities[]="Alamogordo"; +$aCities[]="Albany"; +$aCities[]="Albany"; +$aCities[]="Albany"; +$aCities[]="Albuquerque"; +$aCities[]="Alexandria"; +$aCities[]="Alhambra"; +$aCities[]="Alhambra"; +$aCities[]="Aliso Viejo"; +$aCities[]="Allentown"; +$aCities[]="Alton"; +$aCities[]="Alturas"; +$aCities[]="Amador City"; +$aCities[]="Amarillo"; +$aCities[]="American Canyon"; +$aCities[]="Ames"; +$aCities[]="Amesbury"; +$aCities[]="Amherst"; +$aCities[]="Amherst"; +$aCities[]="Anaheim"; +$aCities[]="Anchorage"; +$aCities[]="Anderson"; +$aCities[]="Anderson"; +$aCities[]="Andover"; +$aCities[]="Angels Camp"; +$aCities[]="Ann Arbor"; +$aCities[]="Annapolis"; +$aCities[]="Anniston"; +$aCities[]="Antioch"; +$aCities[]="Apex"; +$aCities[]="Apple Valley"; +$aCities[]="Appleton"; +$aCities[]="Appleton"; +$aCities[]="Appleton"; +$aCities[]="Appomattox"; +$aCities[]="Arcadia"; +$aCities[]="Arcata"; +$aCities[]="Arlington"; +$aCities[]="Arlington"; +$aCities[]="Arlington"; +$aCities[]="Armonk"; +$aCities[]="Arnaudville"; +$aCities[]="Arnold"; +$aCities[]="Arroyo Grande"; +$aCities[]="Artesia"; +$aCities[]="Arvin"; +$aCities[]="Asbury Park"; +$aCities[]="Asheville"; +$aCities[]="Ashland"; +$aCities[]="Aspen"; +$aCities[]="Assonet"; +$aCities[]="Atascadero"; +$aCities[]="Athens"; +$aCities[]="Athens"; +$aCities[]="Atherton"; +$aCities[]="Atlanta"; +$aCities[]="Atlantic City"; +$aCities[]="Attica"; +$aCities[]="Atwater"; +$aCities[]="Auburn"; +$aCities[]="Auburn"; +$aCities[]="Augusta"; +$aCities[]="Augusta"; +$aCities[]="Aurora"; +$aCities[]="Austin"; +$aCities[]="Autaugaville"; +$aCities[]="Ava"; +$aCities[]="Avalon"; +$aCities[]="Ave Maria"; +$aCities[]="Avenal"; +$aCities[]="Avon"; +$aCities[]="Avondale"; +$aCities[]="Azusa"; +$aCities[]="Bakersfield"; +$aCities[]="Baltimore"; +$aCities[]="Baton Rouge"; +$aCities[]="Bay Minette"; +$aCities[]="Berkeley"; +$aCities[]="Bessemer"; +$aCities[]="Billings"; +$aCities[]="Billingsley"; +$aCities[]="Biloxi"; +$aCities[]="Birmingham"; +$aCities[]="Bismarck"; +$aCities[]="Boise"; +$aCities[]="Boston"; +$aCities[]="Branson"; +$aCities[]="Brownsville"; +$aCities[]="Buffalo"; +$aCities[]="Burlington"; +$aCities[]="Cambridge"; +$aCities[]="Canton"; +$aCities[]="Carmel"; +$aCities[]="Carson City"; +$aCities[]="Casper"; +$aCities[]="Cedar Rapids"; +$aCities[]="Champaign"; +$aCities[]="Charleston"; +$aCities[]="Charleston"; +$aCities[]="Charlotte"; +$aCities[]="Charlottesville"; +$aCities[]="Chattanooga"; +$aCities[]="Cheyenne"; +$aCities[]="Chicago"; +$aCities[]="Cicero"; +$aCities[]="Cincinnati"; +$aCities[]="Cleveland"; +$aCities[]="Colby"; +$aCities[]="Colorado Springs"; +$aCities[]="Columbia"; +$aCities[]="Columbus"; +$aCities[]="Concord"; +$aCities[]="Corpus Christi"; +$aCities[]="Cullman"; +$aCities[]="Dallas"; +$aCities[]="Daphne"; +$aCities[]="Davenport"; +$aCities[]="Dayton"; +$aCities[]="Daytona Beach"; +$aCities[]="Denver"; +$aCities[]="Des Moines"; +$aCities[]="Detroit"; +$aCities[]="Dodge City"; +$aCities[]="Dothan"; +$aCities[]="Dover"; +$aCities[]="Duluth"; +$aCities[]="El Paso"; +$aCities[]="Enterprise"; +$aCities[]="Érié"; +$aCities[]="Eugene"; +$aCities[]="Evansville"; +$aCities[]="Fairfield"; +$aCities[]="Fairbanks"; +$aCities[]="Fargo"; +$aCities[]="Fayetteville"; +$aCities[]="Fayetteville"; +$aCities[]="Flagstaff"; +$aCities[]="Flint"; +$aCities[]="Fort Collins"; +$aCities[]="Fort Lauderdale"; +$aCities[]="Fort Worth"; +$aCities[]="Frankfort"; +$aCities[]="Fresno"; +$aCities[]="Grand Rapids"; +$aCities[]="Great Falls"; +$aCities[]="Green Bay"; +$aCities[]="Greensboro"; +$aCities[]="Greenville"; +$aCities[]="Harrisburg"; +$aCities[]="Hartford"; +$aCities[]="Hays"; +$aCities[]="Helena"; +$aCities[]="Honolulu"; +$aCities[]="Hoover"; +$aCities[]="Hot Springs"; +$aCities[]="Houston"; +$aCities[]="Huntington"; +$aCities[]="Huntsville"; +$aCities[]="Jackson"; +$aCities[]="Jacksonville"; +$aCities[]="Jefferson City"; +$aCities[]="Joplin"; +$aCities[]="Juneau"; +$aCities[]="Idaho Falls"; +$aCities[]="Indianapolis"; +$aCities[]="Lafayette"; +$aCities[]="Lancaster"; +$aCities[]="Lansing"; +$aCities[]="Laredo"; +$aCities[]="Las Cruces"; +$aCities[]="Las Vegas"; +$aCities[]="Leavenworth"; +$aCities[]="Lexington"; +$aCities[]="Lincoln"; +$aCities[]="Little Rock"; +$aCities[]="Littleton"; +$aCities[]="Los Alamos"; +$aCities[]="Los Angeles"; +$aCities[]="Louisville"; +$aCities[]="Lubbock"; +$aCities[]="Madison"; +$aCities[]="Manchester"; +$aCities[]="McAllen"; +$aCities[]="Melbourne"; +$aCities[]="Memphis"; +$aCities[]="Mesa"; +$aCities[]="Miami"; +$aCities[]="Milbrook"; +$aCities[]="Milwaukee"; +$aCities[]="Minneapolis"; +$aCities[]="Missoula"; +$aCities[]="Mobile"; +$aCities[]="Modesto"; +$aCities[]="Monterey"; +$aCities[]="Montgomery"; +$aCities[]="Montpelier"; +$aCities[]="Mountain View"; +$aCities[]="Muncie"; +$aCities[]="Nashville"; +$aCities[]="New Bedford"; +$aCities[]="New Haven"; +$aCities[]="Newport"; +$aCities[]="New York"; +$aCities[]="Niagara Falls"; +$aCities[]="Norfolk"; +$aCities[]="La Nouvelle-Orléans"; +$aCities[]="Newark"; +$aCities[]="Oakland"; +$aCities[]="Oklahoma City"; +$aCities[]="Olympia"; +$aCities[]="Omaha"; +$aCities[]="Orem"; +$aCities[]="Orlando"; +$aCities[]="Palm Springs"; +$aCities[]="Palo Alto"; +$aCities[]="Pearl Harbor"; +$aCities[]="Pensacola"; +$aCities[]="Peoria"; +$aCities[]="Philadelphie"; +$aCities[]="Phoenix"; +$aCities[]="Pierre"; +$aCities[]="Pittsburgh"; +$aCities[]="Point du lac"; +$aCities[]="Portland"; +$aCities[]="Portland"; +$aCities[]="Prattville"; +$aCities[]="Providence"; +$aCities[]="Racine"; +$aCities[]="Raleigh"; +$aCities[]="Rapid City"; +$aCities[]="Redding"; +$aCities[]="Redmond"; +$aCities[]="Redwood City"; +$aCities[]="Reno"; +$aCities[]="Richmond"; +$aCities[]="Roanoke"; +$aCities[]="Rochester"; +$aCities[]="Rockford"; +$aCities[]="Sacramento"; +$aCities[]="Saint Louis"; +$aCities[]="Saint Paul"; +$aCities[]="Salem"; +$aCities[]="Salina"; +$aCities[]="Salt Lake City"; +$aCities[]="San Antonio"; +$aCities[]="San Bernardino"; +$aCities[]="San Diego"; +$aCities[]="San Francisco"; +$aCities[]="San José"; +$aCities[]="San Luis Obispo"; +$aCities[]="San Mateo"; +$aCities[]="Santa Barbara"; +$aCities[]="Santa Cruz"; +$aCities[]="Santa Fe"; +$aCities[]="Sarasota"; +$aCities[]="Saratoga"; +$aCities[]="Savannah"; +$aCities[]="Scranton"; +$aCities[]="Seattle"; +$aCities[]="Shreveport"; +$aCities[]="Sioux Falls"; +$aCities[]="South Bend"; +$aCities[]="Spokane"; +$aCities[]="Springfield"; +$aCities[]="Springfield"; +$aCities[]="Springfield"; +$aCities[]="Stamford"; +$aCities[]="Stockton"; +$aCities[]="Syracuse"; +$aCities[]="Tacoma"; +$aCities[]="Tallahassee"; +$aCities[]="Tampa"; +$aCities[]="Taunton"; +$aCities[]="Toledo"; +$aCities[]="Topeka"; +$aCities[]="Trenton"; +$aCities[]="Tucson"; +$aCities[]="Tulsa"; +$aCities[]="Tuscaloosa"; +$aCities[]="Tuskegee"; +$aCities[]="Waco"; +$aCities[]="Washington, DC"; +$aCities[]="Waterbury"; +$aCities[]="Wichita"; +$aCities[]="Williamsburg"; +$aCities[]="Wilmington"; +$aCities[]="Wilmington"; +$aCities[]="Worcester"; +$aCities[]="Babenhausen"; +$aCities[]="Bacharach"; +$aCities[]="Backnang"; +$aCities[]="Bad Aibling"; +$aCities[]="Bad Arolsen"; +$aCities[]="Bad Bentheim"; +$aCities[]="Bad Bergzabern"; +$aCities[]="Bad Berka"; +$aCities[]="Bad Berleburg"; +$aCities[]="Bad Berneck im Fichtelgebirge"; +$aCities[]="Bad Bevensen"; +$aCities[]="Bad Bibra"; +$aCities[]="Bad Blankenburg"; +$aCities[]="Bad Bramstedt"; +$aCities[]="Bad Breisig"; +$aCities[]="Bad Brückenau"; +$aCities[]="Bad Buchau"; +$aCities[]="Bad Camberg"; +$aCities[]="Bad Colberg-Heldburg"; +$aCities[]="Bad Doberan"; +$aCities[]="Bad Driburg"; +$aCities[]="Bad Düben"; +$aCities[]="Bad Dürkheim"; +$aCities[]="Bad Dürrenberg"; +$aCities[]="Bad Dürrheim"; +$aCities[]="Bad Elster"; +$aCities[]="Bad Ems"; +$aCities[]="Baden-Baden"; +$aCities[]="Bad Fallingbostel"; +$aCities[]="Bad Frankenhausen"; +$aCities[]="Bad Freienwalde"; +$aCities[]="Bad Friedrichshall"; +$aCities[]="Bad Gandersheim"; +$aCities[]="Bad Gottleuba-Berggießhübel"; +$aCities[]="Bad Griesbach im Rottal"; +$aCities[]="Bad Grund"; +$aCities[]="Bad Harzburg"; +$aCities[]="Bad Herrenalb"; +$aCities[]="Bad Hersfeld"; +$aCities[]="Bad Homburg vor der Höhe"; +$aCities[]="Bad Honnef"; +$aCities[]="Bad Hönningen"; +$aCities[]="Calau"; +$aCities[]="Calbe"; +$aCities[]="Calw"; +$aCities[]="Camburg"; +$aCities[]="Castrop-Rauxel"; +$aCities[]="Celle"; +$aCities[]="Cham"; +$aCities[]="Chemnitz"; +$aCities[]="Clausthal-Zellerfeld"; +$aCities[]="Cloppenburg"; +$aCities[]="Coburg"; +$aCities[]="Cochem"; +$aCities[]="Coesfeld"; +$aCities[]="Colditz"; +$aCities[]="Coswig"; +$aCities[]="Coswig"; +$aCities[]="Crailsheim"; +$aCities[]="Creglingen"; +$aCities[]="Creussen"; +$aCities[]="Creuzburg"; +$aCities[]="Crimmitschau"; +$aCities[]="Crivitz"; +$aCities[]="Cuxhaven"; +$aCities[]="Bad Iburg"; +$aCities[]="Bad Karlshafen"; +$aCities[]="Bad Kissingen"; +$aCities[]="Bad König"; +$aCities[]="Bad Königshofen im Grabfeld"; +$aCities[]="Bad Kösen"; +$aCities[]="Bad Köstritz"; +$aCities[]="Bad Kötzting"; +$aCities[]="Bad Kreuznach"; +$aCities[]="Bad Krozingen"; +$aCities[]="Bad Laasphe"; +$aCities[]="Bad Langensalza"; +$aCities[]="Bad Lauchstädt"; +$aCities[]="Bad Lausick"; +$aCities[]="Bad Lauterberg im Harz"; +$aCities[]="Bad Liebenstein"; +$aCities[]="Bad Liebenwerda"; +$aCities[]="Bad Liebenzell"; +$aCities[]="Bad Lippspringe"; +$aCities[]="Bad Lobenstein"; +$aCities[]="Bad Marienberg"; +$aCities[]="Bad Mergentheim"; +$aCities[]="Bad Münder am Deister"; +$aCities[]="Bad Münster am Stein-Ebernburg"; +$aCities[]="Bad Münstereifel"; +$aCities[]="Bad Muskau"; +$aCities[]="Bad Nauheim"; +$aCities[]="Bad Nenndorf"; +$aCities[]="Bad Neuenahr-Ahrweiler"; +$aCities[]="Bad Neustadt an der Saale"; +$aCities[]="Bad Oeynhausen"; +$aCities[]="Bad Oldesloe"; +$aCities[]="Bad Orb"; +$aCities[]="Bad Pyrmont"; +$aCities[]="Bad Rappenau"; +$aCities[]="Bad Reichenhall"; +$aCities[]="Bad Rodach"; +$aCities[]="Bad Sachsa"; +$aCities[]="Bad Säckingen"; +$aCities[]="Bad Salzdetfurth"; +$aCities[]="Bad Salzuflen"; +$aCities[]="Bad Salzungen"; +$aCities[]="Bad Saulgau"; +$aCities[]="Bad Schandau"; +$aCities[]="Bad Schmiedeberg"; +$aCities[]="Bad Schussenried"; +$aCities[]="Bad Schwalbach"; +$aCities[]="Bad Schwartau"; +$aCities[]="Bad Segeberg"; +$aCities[]="Bad Soden am Taunus"; +$aCities[]="Bad Soden-Salmünster"; +$aCities[]="Bad Sooden-Allendorf"; +$aCities[]="Bad Staffelstein"; +$aCities[]="Bad Sulza"; +$aCities[]="Bad Sülze"; +$aCities[]="Bad Teinach-Zavelstein"; +$aCities[]="Bad Tennstedt"; +$aCities[]="Bad Tölz"; +$aCities[]="Bad Urach"; +$aCities[]="Bad Vilbel"; +$aCities[]="Bad Waldsee"; +$aCities[]="Bad Wildbad"; +$aCities[]="Bad Wildungen"; +$aCities[]="Bad Wilsnack"; +$aCities[]="Bad Wimpfen"; +$aCities[]="Bad Windsheim"; +$aCities[]="Bad Wörishofen"; +$aCities[]="Bad Wünnenberg"; +$aCities[]="Bad Wurzach"; +$aCities[]="Baesweiler"; +$aCities[]="Baiersdorf"; +$aCities[]="Balingen"; +$aCities[]="Ballenstedt"; +$aCities[]="Balve"; +$aCities[]="Bamberg"; +$aCities[]="Barby"; +$aCities[]="Bargteheide"; +$aCities[]="Barmstedt"; +$aCities[]="Bärnau"; +$aCities[]="Barntrup"; +$aCities[]="Barsinghausen"; +$aCities[]="Barth"; +$aCities[]="Baruth/Mark"; +$aCities[]="Bassum"; +$aCities[]="Battenberg"; +$aCities[]="Baumholder"; +$aCities[]="Baunach"; +$aCities[]="Baunatal"; +$aCities[]="Bautzen"; +$aCities[]="Bayreuth"; +$aCities[]="Bebra"; +$aCities[]="Beckum"; +$aCities[]="Bedburg"; +$aCities[]="Beelitz"; +$aCities[]="Beerfelden"; +$aCities[]="Beeskow"; +$aCities[]="Beilngries"; +$aCities[]="Beilstein"; +$aCities[]="Belgern"; +$aCities[]="Belzig"; +$aCities[]="Bendorf"; +$aCities[]="Benneckenstein"; +$aCities[]="Bensheim"; +$aCities[]="Berching"; +$aCities[]="Berga/Elster"; +$aCities[]="Bergen"; +$aCities[]="Bergen auf Rügen"; +$aCities[]="Bergheim"; +$aCities[]="Bergisch Gladbach"; +$aCities[]="Bergkamen"; +$aCities[]="Bergneustadt"; +$aCities[]="Berka/Werra"; +$aCities[]="Berlin"; +$aCities[]="Bernau bei Berlin"; +$aCities[]="Bernburg"; +$aCities[]="Bernkastel-Kues"; +$aCities[]="Bernsdorf"; +$aCities[]="Bernstadt a. d. Eigen"; +$aCities[]="Bersenbrück"; +$aCities[]="Besigheim"; +$aCities[]="Betzdorf"; +$aCities[]="Betzenstein"; +$aCities[]="Beverungen"; +$aCities[]="Bexbach"; +$aCities[]="Biberach an der Riß"; +$aCities[]="Biedenkopf"; +$aCities[]="Bielefeld"; +$aCities[]="Biesenthal"; +$aCities[]="Bietigheim-Bissingen"; +$aCities[]="Billerbeck"; +$aCities[]="Bingen am Rhein"; +$aCities[]="Birkenfeld"; +$aCities[]="Bischofsheim an der Rhön"; +$aCities[]="Bischofswerda"; +$aCities[]="Bismark"; +$aCities[]="Bitburg"; +$aCities[]="Bitterfeld"; +$aCities[]="Blankenburg"; +$aCities[]="Blankenhain"; +$aCities[]="Bleckede"; +$aCities[]="Bleicherode"; +$aCities[]="Blieskastel"; +$aCities[]="Blomberg"; +$aCities[]="Blumberg"; +$aCities[]="Bobingen"; +$aCities[]="Böblingen"; +$aCities[]="Bocholt"; +$aCities[]="Bochum"; +$aCities[]="Bockenem"; +$aCities[]="Bodenwerder"; +$aCities[]="Bogen"; +$aCities[]="Böhlen"; +$aCities[]="Boizenburg/Elbe"; +$aCities[]="Bonn"; +$aCities[]="Bonndorf im Schwarzwald"; +$aCities[]="Bönnigheim"; +$aCities[]="Bopfingen"; +$aCities[]="Boppard"; +$aCities[]="Borgentreich"; +$aCities[]="Borgholzhausen"; +$aCities[]="Borken"; +$aCities[]="Borken"; +$aCities[]="Borkum"; +$aCities[]="Borna"; +$aCities[]="Bornheim"; +$aCities[]="Bottrop"; +$aCities[]="Boxberg"; +$aCities[]="Brackenheim"; +$aCities[]="Brake"; +$aCities[]="Brakel"; +$aCities[]="Bramsche"; +$aCities[]="Brandenburg an der Havel"; +$aCities[]="Brand-Erbisdorf"; +$aCities[]="Brandis"; +$aCities[]="Braubach"; +$aCities[]="Braunfels"; +$aCities[]="Braunlage"; +$aCities[]="Bräunlingen"; +$aCities[]="Braunsbedra"; +$aCities[]="Braunschweig"; +$aCities[]="Breckerfeld"; +$aCities[]="Bredstedt"; +$aCities[]="Brehna"; +$aCities[]="Breisach am Rhein"; +$aCities[]="Bremen"; +$aCities[]="Bremerhaven"; +$aCities[]="Bremervörde"; +$aCities[]="Bretten"; +$aCities[]="Breuberg"; +$aCities[]="Brilon"; +$aCities[]="Brotterode"; +$aCities[]="Bruchköbel"; +$aCities[]="Bruchsal"; +$aCities[]="Brück"; +$aCities[]="Brüel"; +$aCities[]="Brühl"; +$aCities[]="Brunsbüttel"; +$aCities[]="Brüssow"; +$aCities[]="Buchen"; +$aCities[]="Buchholz in der Nordheide"; +$aCities[]="Buchloe"; +$aCities[]="Bückeburg"; +$aCities[]="Buckow"; +$aCities[]="Büdelsdorf"; +$aCities[]="Büdingen"; +$aCities[]="Bühl"; +$aCities[]="Bünde"; +$aCities[]="Büren"; +$aCities[]="Burg"; +$aCities[]="Burgau"; +$aCities[]="Burgbernheim"; +$aCities[]="Burgdorf"; +$aCities[]="Bürgel"; +$aCities[]="Burghausen"; +$aCities[]="Burgkunstadt"; +$aCities[]="Burglengenfeld"; +$aCities[]="Burgstädt"; +$aCities[]="Burg Stargard"; +$aCities[]="Burgwedel"; +$aCities[]="Burladingen"; +$aCities[]="Burscheid"; +$aCities[]="Bürstadt"; +$aCities[]="Buttelstedt"; +$aCities[]="Buttstädt"; +$aCities[]="Butzbach"; +$aCities[]="Bützow"; +$aCities[]="Buxtehude"; + +?> diff --git a/business/incident.business.php b/business/incident.business.php new file mode 100644 index 000000000..c41d7dd6b --- /dev/null +++ b/business/incident.business.php @@ -0,0 +1,367 @@ + + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +//////////////////////////////////////////////////////////////////////////////////// +/** +* An Incident Ticket +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizIncidentTicket extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Incident", + "description" => "Incident ticket", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "ticket_status", + "reconc_keys" => array("title"), + "db_table" => "incident", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/ticket.html", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"TicketID", "description"=>"Refence number ofr this incident", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("title", array("label"=>"Title", "description"=>"Overview of the Incident", "allowed_values"=>null, "sql"=>"title", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of the Incident", "allowed_values"=>new ValueSetEnum("Network,Server,Desktop,Application"), "sql"=>"type", "default_value"=>"Server", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("customer_id", array("targetclass"=>"bizOrganization", "label"=>"Customer", "description"=>"who is impacted by the ticket", "allowed_values"=>null, "sql"=>"customer", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("customer_name", array("label"=>"Customer", "description"=>"Name of the customer impacted by this ticket", "allowed_values"=>null, "extkey_attcode"=> 'customer_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeEnum("ticket_status", array("label"=>"Status", "description"=>"Status of the ticket", "allowed_values"=>new ValueSetEnum("New, Assigned, WorkInProgress, Closed"), "sql"=>"ticket_status", "default_value"=>"New", "is_null_allowed"=>false, "depends_on"=>array()))); + // SetPossibleValues("status",array("Open","Monitored","Closed")); + MetaModel::Init_AddAttribute(new AttributeText("initial_situation", array("label"=>"Initial Situation", "description"=>"Initial situation of the Incident", "allowed_values"=>null, "sql"=>"initial_situation", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("current_situation", array("label"=>"Current Situation", "description"=>"Current situation of the Incident", "allowed_values"=>null, "sql"=>"current_situation", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("start_date", array("label"=>"Starting date", "description"=>"Incident starting date", "allowed_values"=>null, "sql"=>"start_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + // définir une date de défaut à maintenant, alias creation ou modification du ticket + MetaModel::Init_AddAttribute(new AttributeDate("last_update", array("label"=>"Last update", "description"=>"last time the Ticket was modified", "allowed_values"=>null, "sql"=>"last_update", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("next_update", array("label"=>"Next update", "description"=>"next time the Ticket is expected to be modified", "allowed_values"=>null, "sql"=>"next_update", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeDate("end_date", array("label"=>"Closed Date", "description"=>"Date when the Ticket was closed", "allowed_values"=>null, "sql"=>"closed_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("caller_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Caller", "description"=>"person that trigger incident", "allowed_values"=>null, "sql"=>"caller_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("caller_mail", array("label"=>"Caller", "description"=>"Person that trigger this incident", "allowed_values"=>null, "extkey_attcode"=> 'caller_id', "target_attcode"=>"email"))); + + MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Impact", "description"=>"Impact of the Incident", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("workgroup_id", array("targetclass"=>"bizWorkgroup", "jointype"=> "", "label"=>"Workgroup", "description"=>"which workgroup is owning ticket", "allowed_values"=>null, "sql"=>"workgroup_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("workgroup_name", array("label"=>"Managed by Workgroup", "description"=>"name of workgroup managing the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'workgroup_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("agent_id", array("targetclass"=>"bizPerson", "jointype"=> "", "label"=>"Agent", "description"=>"who is managing the ticket", "allowed_values"=>null, "sql"=>"agent_id", "is_null_allowed"=>true, "depends_on"=>array("workgroup_id")))); + MetaModel::Init_AddAttribute(new AttributeExternalField("agent_mail", array("label"=>"Managed by Agent", "description"=>"mail of agent managing the Ticket", "allowed_values"=>null, "extkey_attcode"=> 'agent_id', "target_attcode"=>"email"))); + // Comment afficher le first + last name de l'agent ? Est-ce utile d'ajouter ce champ? + MetaModel::Init_AddAttribute(new AttributeText("action_log", array("label"=>"Action Logs", "description"=>"List all action performed during the incident", "allowed_values"=>null, "sql"=>"action_log", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("severity", array("label"=>"Severity", "description"=>"Field defining the criticity if the incident", "allowed_values"=>new ValueSetEnum("critical,medium,low"), "sql"=>"criticity", "default_value"=>"low", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("assignment_count", array("label"=>"Assignment Count", "description"=>"Number of times this ticket was assigned or reassigned", "allowed_values"=>null, "sql"=>"assignment_count", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeText("resolution", array("label"=>"Resolution", "description"=>"Description of the resolution", "allowed_values"=>null, "sql"=>"resolution", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("impacted_infra_manual", array("label"=>"Impacted Infrastructure", "description"=>"CIs that are not meeting the SLA", "linked_class"=>"lnkInfraTicket", "ext_key_to_me"=>"ticket_id", "ext_key_to_remote"=>"infra_id", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("related_tickets", array("label"=>"Related Tickets", "description"=>"Other incident tickets related to this one", "linked_class"=>"lnkRelatedTicket", "ext_key_to_me"=>"ticket_id", "ext_key_to_remote"=>"rel_ticket_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(/*'impacted_infra_computed',*/ 'impacted_infra_manual')))); + + + //MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("title"); + MetaModel::Init_AddFilterFromAttribute("type"); + MetaModel::Init_AddFilterFromAttribute("customer_id"); + MetaModel::Init_AddFilterFromAttribute("caller_id"); + MetaModel::Init_AddFilterFromAttribute("ticket_status"); + MetaModel::Init_AddFilterFromAttribute("start_date"); + MetaModel::Init_AddFilterFromAttribute("last_update"); + MetaModel::Init_AddFilterFromAttribute("end_date"); + MetaModel::Init_AddFilterFromAttribute("workgroup_id"); + MetaModel::Init_AddFilterFromAttribute("agent_id"); + MetaModel::Init_AddFilterFromAttribute("severity"); + MetaModel::Init_AddFilterFromAttribute("assignment_count"); + + // doit-on aussi ajouter un filtre sur les extfields lié à une extkey ? ici le name de l'agent? + + // Display lists + MetaModel::Init_SetZListItems('details', array('name','title', 'customer_id', 'type','ticket_status', 'severity','start_date', 'initial_situation', 'current_situation','caller_id', 'impact', 'last_update', 'next_update','end_date', 'assignment_count', 'workgroup_id','agent_id','action_log','resolution')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('name', 'title', 'customer_id', 'type','ticket_status','severity','start_date', 'initial_situation')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'title', 'customer_id', 'caller_id','type', 'ticket_status', 'severity','start_date', 'last_update','end_date','agent_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'title', 'customer_id','caller_id','type','ticket_status', 'severity','start_date', 'last_update', 'end_date','agent_id')); // Criteria of the advanced search form + + // State machine + MetaModel::Init_DefineState("New", array("label"=>"New (Unassigned)", "description"=>"Newly created ticket", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY, 'assignment_count' => OPT_ATT_HIDDEN, 'end_date' => OPT_ATT_HIDDEN, 'next_update' => OPT_ATT_HIDDEN, 'last_update' => OPT_ATT_HIDDEN, + "title"=>OPT_ATT_MANDATORY, "customer_id"=>OPT_ATT_MANDATORY, "caller_id"=>OPT_ATT_MANDATORY, "initial_situation"=>OPT_ATT_MANDATORY, "start_date"=>OPT_ATT_MANDATORY, "workgroup_id"=>OPT_ATT_MANDATORY, + "severity"=>OPT_ATT_MANDATORY, "agent_id"=>OPT_ATT_HIDDEN,"impacted_infra_manual"=>OPT_ATT_MANDATORY, "related_tickets"=>OPT_ATT_MUSTPROMPT))); + MetaModel::Init_DefineState("Assigned", array("label"=>"Assigned", "description"=>"Ticket is assigned to somebody", "attribute_inherit"=>null, + "attribute_list"=>array('name' => OPT_ATT_READONLY, "title"=>OPT_ATT_READONLY, "customer_id"=>OPT_ATT_READONLY, "caller_id"=>OPT_ATT_READONLY, "initial_situation"=>OPT_ATT_READONLY, "start_date"=>OPT_ATT_READONLY,'assignment_count' => OPT_ATT_READONLY,'end_date' => OPT_ATT_HIDDEN, "workgroup_id"=>OPT_ATT_MUSTCHANGE, "agent_id"=>OPT_ATT_MUSTCHANGE))); + MetaModel::Init_DefineState("WorkInProgress", array("label"=>"Work In Progress", "description"=>"Work is in progress", "attribute_inherit"=>null, "attribute_list"=>array("title"=>OPT_ATT_READONLY, "customer_id"=>OPT_ATT_READONLY, "caller_id"=>OPT_ATT_READONLY, "initial_situation"=>OPT_ATT_READONLY,'end_date' => OPT_ATT_HIDDEN, "start_date"=>OPT_ATT_READONLY,"workgroup_id"=>OPT_ATT_MANDATORY, "agent_id"=>OPT_ATT_MANDATORY))); + MetaModel::Init_DefineState("Closed", array("label"=>"Closed", "description"=>"Ticket is closed", "attribute_inherit"=>null, "attribute_list"=>array("workgroup_id"=>OPT_ATT_MANDATORY, "agent_id"=>OPT_ATT_MANDATORY, "resolution"=>OPT_ATT_MANDATORY, "end_date"=>OPT_ATT_MANDATORY))); + + MetaModel::Init_DefineStimulus("ev_assign", new StimulusUserAction(array("label"=>"Assign this ticket", "description"=>"Assign this ticket to a group and an agent"))); + MetaModel::Init_DefineStimulus("ev_reassign", new StimulusUserAction(array("label"=>"Reassign this ticket", "description"=>"Reassign this ticket to a different group and agent"))); + MetaModel::Init_DefineStimulus("ev_start_working", new StimulusUserAction(array("label"=>"Work on this ticket", "description"=>"Start working on this ticket"))); + MetaModel::Init_DefineStimulus("ev_close", new StimulusUserAction(array("label"=>"Close this ticket", "description"=>"Close/resolve this ticket"))); + + MetaModel::Init_DefineTransition("New", "ev_assign", array("target_state"=>"Assigned", "actions"=>array('IncrementAssignmentCount'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Assigned", "ev_reassign", array("target_state"=>"Assigned", "actions"=>array('IncrementAssignmentCount'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Assigned", "ev_start_working", array("target_state"=>"WorkInProgress", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("WorkInProgress", "ev_reassign", array("target_state"=>"Assigned", "actions"=>array('IncrementAssignmentCount'), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("WorkInProgress", "ev_close", array("target_state"=>"Closed", "actions"=>array('SetClosureDate'), "user_restriction"=>null)); + + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('customer_id', $oGenerator->GetOrganizationId()); + $this->Set('title', $oGenerator->GenerateString("enum(Site,Server,Line)| |enum(is down,is flip-flopping,is not responding)")); + $this->Set('agent_id', $oGenerator->GenerateKey("bizPerson", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('ticket_status', $oGenerator->GenerateString("enum(Open,Closed,Closed,Monitored)")); + $this->Set('start_date', $oGenerator->GenerateString("2007-|number(07-12)|-|number(01-30)| |number(07-12)|:|number(00-59)|:|number(00-59)")); + $this->Set('last_update', $oGenerator->GenerateString("2007-|number(07-12)|-|number(01-30)| |number(07-12)|:|number(00-59)|:|number(00-59)")); + $this->Set('end_date', $oGenerator->GenerateString("2007-|number(07-12)|-|number(01-30)| |number(07-12)|:|number(00-59)|:|number(00-59)")); + } + + public static function GetUIPage() + { + return './UI.php'; + } + + // State machine actions + public function IncrementAssignmentCount($sStimulusCode) + { + $this->Set('assignment_count', $this->Get('assignment_count') + 1); + return true; + } + + public function SetClosureDate($sStimulusCode) + { + $this->Set('end_date', time()); + return true; + } + + public function ComputeFields() + { + if ($this->GetKey() > 0) + { + $sName = sprintf('I-%06d', $this->GetKey()); + } + else + { + $sName = "Id not set"; + } + $this->Set('name', $sName); + } +} + + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Infra and a Incident +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkRelatedTicket extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Related Ticket", + "description" => "Ticket related to a ticket", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "impact", // ???? + "state_attcode" => "", + "reconc_keys" => array("impact"), // ???? + "db_table" => "related_ticket", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("rel_ticket_id", array("targetclass"=>"bizIncidentTicket", "jointype"=> '', "label"=>"Related Ticket id", "description"=>"The related ticket", "allowed_values"=>null, "sql"=>"rel_ticket_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("rel_ticket_name", array("label"=>"Related ticket", "description"=>"Name of the related ticket", "allowed_values"=>null, "extkey_attcode"=> 'rel_ticket_id', "target_attcode"=>"title"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("ticket_id", array("targetclass"=>"bizIncidentTicket", "jointype"=> '', "label"=>"Ticket #", "description"=>"Ticket number", "allowed_values"=>null, "sql"=>"ticket_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ticket_name", array("label"=>"Ticket name", "description"=>"Name of the ticket", "allowed_values"=>null, "extkey_attcode"=> 'ticket_id', "target_attcode"=>"title"))); + MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Impact", "description"=>"Impact on the related ticket", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("rel_ticket_id"); + MetaModel::Init_AddFilterFromAttribute("ticket_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('rel_ticket_id', 'ticket_id', 'impact')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('rel_ticket_id', 'ticket_id', 'impact')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('rel_ticket_id', 'ticket_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('rel_ticket_id', 'ticket_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('infra_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('ticket_id', $oGenerator->GenerateKey("bizIncidentTicket", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('impact', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } + +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Infra and a Incident +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkInfraTicket extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Infra Ticket", + "description" => "Infra impacted by a ticket", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "impact", // ???? + "state_attcode" => "", + "reconc_keys" => array("impact"), // ???? + "db_table" => "infra_ticket", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("infra_id", array("targetclass"=>"logInfra", "jointype"=> '', "label"=>"Infrastructure", "description"=>"The infrastructure impacted", "allowed_values"=>null, "sql"=>"infra_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_name", array("label"=>"Infrastructure name", "description"=>"Name of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("ticket_id", array("targetclass"=>"bizIncidentTicket", "jointype"=> '', "label"=>"Ticket #", "description"=>"Ticket number", "allowed_values"=>null, "sql"=>"ticket_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ticket_name", array("label"=>"Ticket name", "description"=>"Name of the ticket", "allowed_values"=>null, "extkey_attcode"=> 'ticket_id', "target_attcode"=>"title"))); + MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Impact", "description"=>"Level of impact of the infra by the related ticket", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("infra_id"); + MetaModel::Init_AddFilterFromAttribute("ticket_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('infra_id', 'ticket_id', 'impact')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('infra_id', 'ticket_id', 'impact')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('infra_id', 'ticket_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('infra_id', 'ticket_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('infra_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('ticket_id', $oGenerator->GenerateKey("bizIncidentTicket", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('impact', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } + +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Contqct and a Incident +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkContactTicket extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Contact Ticket", + "description" => "Contacts to be notify for a ticket", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "role", // ???? + "state_attcode" => "", + "reconc_keys" => array("role"), // ???? + "db_table" => "contact_ticket", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contact_id", array("targetclass"=>"bizContact", "jointype"=> '', "label"=>"Contact", "description"=>"Contact to Notify", "allowed_values"=>null, "sql"=>"contact_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("label"=>"Contact email", "description"=>"Mail for the contact", "allowed_values"=>null, "extkey_attcode"=> 'contact_id', "target_attcode"=>"email"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("ticket_id", array("targetclass"=>"bizIncidentTicket", "jointype"=> '', "label"=>"Ticket #", "description"=>"Ticket number", "allowed_values"=>null, "sql"=>"ticket_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("ticket_name", array("label"=>"Ticket name", "description"=>"Name of the ticket", "allowed_values"=>null, "extkey_attcode"=> 'ticket_id', "target_attcode"=>"title"))); + MetaModel::Init_AddAttribute(new AttributeString("role", array("label"=>"Role", "description"=>"Role of the contact", "allowed_values"=>null, "sql"=>"role", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("contact_id"); + MetaModel::Init_AddFilterFromAttribute("ticket_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('contact_id', 'ticket_id', 'role')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('contact_id', 'ticket_id', 'role')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('contact_id', 'ticket_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('contact_id', 'ticket_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('infra_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('ticket_id', $oGenerator->GenerateKey("bizIncidentTicket", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('impact', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } + +} +//////////////////////////////////////////////////////////////////////////////////// +//** +//* A workgroup is a queue in a given call tracking system +//* It belongs to a team and a given organization +//////////////////////////////////////////////////////////////////////////////////// +class bizWorkgroup extends logRealObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Workgroup", + "description" => "Call tracking workgroup", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "workgroups", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalField("org_name", array("label"=>"Organization", "description"=>"Company / Department owning this object", "allowed_values"=>null, "extkey_attcode"=> 'org_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("team_id", array("targetclass"=>"bizTeam", "label"=>"Team", "description"=>"Team owning the workgroup", "allowed_values"=>null, "sql"=>"team_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("team_name", array("label"=>"Team name", "description"=>"name of the team", "allowed_values"=>null, "extkey_attcode"=> 'team_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("role", array("label"=>"Role", "description"=>"Role of this work group", "allowed_values"=>new ValueSetEnum("1st level support,2nd level support,3rd level support"), "sql"=>"role", "default_value"=>"1st level support", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("org_name"); + MetaModel::Init_AddFilterFromAttribute("team_id"); + MetaModel::Init_AddFilterFromAttribute("role"); + + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'team_id', 'role')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'team_id','role')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'team_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'team_id','role')); // Criteria of the advanced search form + + } +} + + + +?> diff --git a/business/itop.business.class.inc.php b/business/itop.business.class.inc.php new file mode 100644 index 000000000..07dbafb4f --- /dev/null +++ b/business/itop.business.class.inc.php @@ -0,0 +1,1633 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +/** + * Possible values for the statuses of objects + */ +$oAllowedStatuses = new ValueSetEnum('production,implementation,obsolete'); + +/** + * Relation graphs + */ +MetaModel::RegisterRelation("impacts", array("description"=>"objects being functionaly impacted", "verb_down"=>"impacts", "verb_up"=>"is impacted by")); + +//////////////////////////////////////////////////////////////////////////////////// +/** +* An organization that owns some objects +* +* An organization "owns" some persons (its employees) but also some other objects +* (its assets) like buildings, computers, furniture... +* the services that they provides, the contracts/OLA they have signed as customer +* +* Organization ownership might be used to manage the R/W access to the object +*/ +//////////////////////////////////////////////////////////////////////////////////// +/** + * itop.business.class.inc.php + * User defined objects, implements the business need + * + * @package iTopBizModelSamples + * @author Erwan Taloc + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class bizOrganization extends cmdbAbstractObject +{ + public static function Init() + { + global $oAllowedStatuses; + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Organization", + "description" => "Organizational structure: can be Company and/or Department", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("name"), + "db_table" => "organizations", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"Name", "description"=>"Common name", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array() ))); + MetaModel::Init_AddAttribute(new AttributeString("code", array("label"=>"Code", "description"=>"Organization code (Siret, DUNS,...)", "allowed_values"=>null, "sql"=>"code", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array() ))); + MetaModel::Init_AddAttribute(new AttributeEnum("status", array("label"=>"Status", "description"=>"Lifecycle status", "allowed_values"=>$oAllowedStatuses, "sql"=>"status", "default_value"=>"implementation", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("parent_id", array("targetclass"=>"bizOrganization", "label"=>"Parent Id", "description"=>"Parent organization", "allowed_values"=>null, "sql"=>"parent_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("parent_name", array("label"=>"Parent Name", "description"=>"Name of the parent organization", "allowed_values"=>null, "extkey_attcode"=> 'parent_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("code"); + MetaModel::Init_AddFilterFromAttribute("status"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'code', 'status', 'parent_id')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'parent_id')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('preview', array('name', 'status', 'parent_id')); // Attributes to be displayed for a preview + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'code', 'status')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'code', 'status')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + //$this->SetKey($oGenerator->GetOrganizationCode()); + $this->Set('name', $oGenerator->GetOrganizationName()); + $this->Set('code', $oGenerator->GetOrganizationCode()); + $this->Set('status', 'implementation'); + $this->Set('parent_id', 1); + + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Class of objects owned by some organization +* +* This is the root class of all the objects that can be "owned" by an organization +* +* A Real Object +* can be supported by Contacts, having a specific role (same contact with multiple roles?) +* can be documented by Documents +*/ +//////////////////////////////////////////////////////////////////////////////////// +/** + * itop.business.class.inc.php + * User defined objects, implements the business need + * + * @package iTopBizModelSamples + * @author Erwan Taloc + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class logRealObject extends cmdbAbstractObject +{ + public static function Init() + { + global $oAllowedStatuses; + + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Object", + "description" => "Any CMDB object", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("name"), + "db_table" => "objects", + "db_key_field" => "id", + "db_finalclass_field" => "obj_class", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"Name", "description"=>"Common name", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("status", array("label"=>"Status", "description"=>"Lifecycle status", "allowed_values"=>$oAllowedStatuses, "sql"=>"status", "default_value"=>"implementation", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("org_id", array("targetclass"=>"bizOrganization", "label"=>"Organization Id", "description"=>"ID of the object owner organization", "allowed_values"=>new ValueSetObjects("bizOrganization: status Contains 'implementation'", 'name', array('name'=>true)), "sql"=>"org_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("org_name", array("label"=>"Organization", "description"=>"Company / Department owning this object", "allowed_values"=>null, "extkey_attcode"=> 'org_id', "target_attcode"=>"name"))); + + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("status"); + MetaModel::Init_AddFilterFromAttribute("org_id"); + MetaModel::Init_AddFilterFromAttribute("org_name"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'status', 'org_id')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('preview', array('name', 'status', 'org_id')); // Attributes to be displayed for a preview + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('org_id', $oGenerator->GetOrganizationId()); + $this->Set('name', ""); + $this->Set('status', $oGenerator->GenerateString("enum(implementation,production)")); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Any kind of thing that can be contacted (person, team, hotline...) +* A contact can: +* be linked to any Real Object with a role +* be part of a GroupContact +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizContact extends logRealObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Contact", + "description" => "Contact", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "contacts", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalField("org_name", array("label"=>"Organization", "description"=>"Company / Department of the contact", "allowed_values"=>null, "extkey_attcode"=> 'org_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("email", array("label"=>"eMail", "description"=>"Email address", "allowed_values"=>null, "sql"=>"email", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("phone", array("label"=>"Phone", "description"=>"Telephone", "allowed_values"=>null, "sql"=>"telephone", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("location_id", array("targetclass"=>"bizLocation", "label"=>"Location Id", "description"=>"Id of the location where the contact is located", "allowed_values"=>null, "sql"=>"location_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("location_name", array("label"=>"Location Name", "description"=>"Name of the location where the contact is located", "allowed_values"=>null, "extkey_attcode"=> 'location_id', "target_attcode"=>"name"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("org_name"); + MetaModel::Init_AddFilterFromAttribute("email"); + MetaModel::Init_AddFilterFromAttribute("phone"); + MetaModel::Init_AddFilterFromAttribute("location_id"); + MetaModel::Init_AddFilterFromAttribute("location_name"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'email', 'location_id', 'phone')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('finalclass', 'name', 'status', 'org_id', 'email', 'location_id', 'phone')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('preview', array('name', 'status', 'org_id')); // Attributes to be displayed for a preview + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'email', 'location_id', 'phone')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('org_id', $oGenerator->GetOrganizationId()); + $this->Set('name', ""); + $this->Set('email', ""); + $this->Set('phone', $oGenerator->GenerateString("enum(+1,+33,+44,+49,+421)| |number(100-999)| |number(000-999)")); + $this->Set('location_id', $oGenerator->GenerateKey("bizLocation", array('org_id' =>$oGenerator->GetOrganizationId() ))); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Physical person only +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizPerson extends bizContact +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Person", + "description" => "Person", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "first_name", "name"), // comment en définir plusieurs + // "reconc_keys" => array("org_name", "employe_number"), + "db_table" => "persons", // Can it use the same physical DB table as any contact ? + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/person.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("first_name", array("label"=>"first Name", "description"=>"First name", "allowed_values"=>null, "sql"=>"first_name", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("employe_number", array("label"=>"Employe Number", "description"=>"employe number", "allowed_values"=>null, "sql"=>"employe_number", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("first_name"); + MetaModel::Init_AddFilterFromAttribute("employe_number"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('first_name', 'name', 'status', 'org_id', 'email', 'location_id', 'phone', 'employe_number')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('first_name', 'name', 'status', 'org_id', 'email', 'location_id', 'phone')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('preview', array('name', 'status', 'org_id')); // Attributes to be displayed for a preview + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('first_name', 'name', 'status', 'email', 'location_id', 'phone', 'employe_number')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('first_name', 'name', 'status', 'email', 'location_id', 'phone', 'employe_number')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + parent::Generate($oGenerator); + $this->Set('name', $oGenerator->GenerateLastName()); + $this->Set('first_name', $oGenerator->GenerateFirstName()); + $this->Set('email', $oGenerator->GenerateEmail($this->Get('first_name'), $this->Get('name'))); + $this->Set('phone', $oGenerator->GenerateString("enum(+1,+33,+44,+49,+421)| |number(100-999)| |number(000-999)")); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* A team is basically a contact which is also a group of contacts +* (and thus a team can contain other teams) +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizTeam extends bizContact +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Team", + "description" => "A group of contacts", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "teams", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/team.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + + MetaModel::Init_InheritFilters(); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'email', 'location_id', 'phone')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'org_id', 'email', 'location_id', 'phone')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'email', 'location_id', 'phone')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form + } +} + + +//////////////////////////////////////////////////////////////////////////////////// +/** +* An electronic document, with version tracking +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizDocument extends logRealObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Document", + "description" => "Document", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "documents", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/document.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalField("org_name", array("label"=>"Organization", "description"=>"Company / Department owning the document", "allowed_values"=>null, "extkey_attcode"=> 'org_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeEnum("scope", array("label"=>"scope", "description"=>"Scope of this document", "allowed_values"=>new ValueSetEnum("organization,hardware support"), "sql"=>"scope", "default_value"=>"organization", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("description", array("label"=>"Description", "description"=>"Service Description", "allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("scope"); + MetaModel::Init_AddFilterFromAttribute("description"); + + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'scope','description')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'org_id', 'scope')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'scope')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'scope')); // Criteria of the advanced search form + + } + +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* A version of an electronic document +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizDocVersion extends cmdbAbstractObject +{ + public static function Init() + { + global $oAllowedStatuses; + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "DocumentVersion", + "description" => "A version of a document", + "key_type" => "autoincrement", + "key_label" => "id", + "name_attcode" => "version_number", + "state_attcode" => "", + "reconc_keys" => array("docname", "version_number"), + "db_table" => "document_versions", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/document.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("document", array("targetclass"=>"bizDocument", "label"=>"document", "description"=>"The main document", "allowed_values"=>null, "sql"=>"document_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("docname", array("label"=>"document name", "description"=>"name of the document", "allowed_values"=>null, "extkey_attcode"=> 'document', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("version_number", array("label"=>"version number", "description"=>"Service name", "allowed_values"=>null, "sql"=>"version_number", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("status", array("label"=>"status", "description"=>"Status", "allowed_values"=>$oAllowedStatuses, "sql"=>"status", "default_value"=>"implementation", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"type", "description"=>"Type", "allowed_values"=>new ValueSetEnum("local,draft"), "sql"=>"type", "default_value"=>"local", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeURL("url", array("label"=>"URL", "description"=>"Hyperlink to the version", "allowed_values"=>null, "target"=>"_blank", "sql"=>"url", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("description", array("label"=>"Description", "description"=>"Service Description", "allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("document"); + MetaModel::Init_AddFilterFromAttribute("docname"); + MetaModel::Init_AddFilterFromAttribute("version_number"); + MetaModel::Init_AddFilterFromAttribute("status"); + MetaModel::Init_AddFilterFromAttribute("type"); + MetaModel::Init_AddFilterFromAttribute("description"); + + MetaModel::Init_SetZListItems('details', array('docname', 'status', 'version_number', 'type','url','description')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('version_number', 'status', 'type', 'url')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('docname', 'type')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('docname', 'type')); // Criteria o + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Object and a Document +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkDocumentRealObject extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "DocumentsLinks", + "description" => "A link between a document and another object", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "link_type", + "state_attcode" => "", + "reconc_keys" => array("doc_name", "object_name"), + "db_table" => "documents_links", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("doc_id", array("targetclass"=>"bizDocument", "label"=>"Document Name", "description"=>"id of the Document", "allowed_values"=>null, "sql"=>"doc_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("doc_name", array("label"=>"Document", "description"=>"name of the document", "allowed_values"=>null, "extkey_attcode"=> 'doc_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("object_id", array("targetclass"=>"logRealObject", "label"=>"object", "description"=>"Object linked", "allowed_values"=>null, "sql"=>"object_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("object_name", array("label"=>"object name", "description"=>"name of the linked object", "allowed_values"=>null, "extkey_attcode"=> 'object_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("link_type", array("label"=>"link_type", "description"=>"Type of the link", "allowed_values"=>null, "sql"=>"link_type", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("doc_id"); + MetaModel::Init_AddFilterFromAttribute("doc_name"); + MetaModel::Init_AddFilterFromAttribute("object_id"); + MetaModel::Init_AddFilterFromAttribute("object_name"); + MetaModel::Init_AddFilterFromAttribute("link_type"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('doc_id', 'object_name', 'link_type')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('doc_id', 'object_name', 'link_type')); // Attributes to be displayed for a list + } +} + + + + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Object and a contact +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkContactRealObject extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "ContactsLinks", + "description" => "A link between a contact and another object", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "role", + "state_attcode" => "", + "reconc_keys" => array("contact_name", "object_name"), + "db_table" => "contacts_links", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("contact_id", array("targetclass"=>"bizContact", "label"=>"Contact", "description"=>"The contact", "allowed_values"=>null, "sql"=>"contact_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("label"=>"Contact name", "description"=>"name of the contact", "allowed_values"=>null, "extkey_attcode"=> 'contact_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_phone", array("label"=>"Phone", "description"=>"Phone number of the contact", "allowed_values"=>null, "extkey_attcode"=> 'contact_id', "target_attcode"=>"phone"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("label"=>"eMail", "description"=>"eMail address of the contact", "allowed_values"=>null, "extkey_attcode"=> 'contact_id', "target_attcode"=>"email"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("object_id", array("targetclass"=>"logRealObject", "label"=>"object", "description"=>"Object linked", "allowed_values"=>null, "sql"=>"object_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("object_name", array("label"=>"Object name", "description"=>"name of the linked object", "allowed_values"=>null, "extkey_attcode"=> 'object_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("role", array("label"=>"Role", "description"=>"Role of the contact", "allowed_values"=>null, "sql"=>"role", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("contact_id"); + MetaModel::Init_AddFilterFromAttribute("contact_name"); + MetaModel::Init_AddFilterFromAttribute("object_id"); + MetaModel::Init_AddFilterFromAttribute("object_name"); + MetaModel::Init_AddFilterFromAttribute("role"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('contact_id', 'contact_phone', 'contact_email', 'object_id', 'role')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('contact_id', 'contact_phone', 'contact_email', 'object_id', 'role')); // Attributes to be displayed for a list + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Any Infrastructure object (bizLocation, bizDevice, bizApplication, bizCircuit, bizInterface) +* An infrastructure object: +* can be covered by an OLA +* can support the delivery of a Service +* can be part of an GroupInfra +*/ +//////////////////////////////////////////////////////////////////////////////////// +class logInfra extends logRealObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Infra", + "description" => "Infrastructure real object", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "infra", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeEnum("severity", array("label"=>"Severity", "description"=>"Severity for this infrastructure", "allowed_values"=>new ValueSetEnum("high,medium,low"), "sql"=>"severity", "default_value"=>"low", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("severity"); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* bizLocation (Region, Country, City, Site, Building, Floor, Room, Rack,...) +* pourrait être mis en plusieurs sous objects, puisqu'une adresse sur region n'a pas trop de sens +* +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizLocation extends logInfra +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Location", + "description" => "Any type of location: Region, Country, City, Site, Building, Floor, Room, Rack,...", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "location", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/location.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeText("address", array("label"=>"Address", "description"=>"The postal address of the location", "allowed_values"=>null, "sql"=>"address", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("country", array("label"=>"Country", "description"=>"Country of the location", "allowed_values"=>null, "sql"=>"country", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("parent_location_id", array("targetclass"=>"bizLocation", "label"=>"Parent Location", "description"=>"where is the real object physically located", "allowed_values"=>null, "sql"=>"parent_location_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("parent_location_name", array("label"=>"Parent location (Name)", "description"=>"name of the parent location", "allowed_values"=>null, "extkey_attcode"=> 'parent_location_id', "target_attcode"=>"name"))); + + // on veut pouvoir rechercher une location qui soit un descendant (pas obligatoirement direct) d'une Location, on fait comment ? + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("country"); + MetaModel::Init_AddFilterFromAttribute("address"); + MetaModel::Init_AddFilterFromAttribute("parent_location_id"); + MetaModel::Init_AddFilterFromAttribute("parent_location_name"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'address', 'country', 'parent_location_id')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'org_id', 'country')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'country', 'parent_location_name')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'address', 'country', 'parent_location_id', 'org_id')); // Criteria of the advanced search form + } + + public function ComputeValues() + { + /* + $this->Set("location_id", $this->GetKey()); + // Houston, I've got an issue, as this field is calculated, I should reload the object... ? + $this->Set("location_name", "abc (to be finalized)"); + */ + } + + function DisplayDetails(web_page $oPage) + { + parent::DisplayDetails($oPage); +/* + parent::DisplayDetails($oPage); + + + + $oSearchFilter = new CMDBSearchFilter('bizServer'); + $oSearchFilter->AddCondition('location_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Servers"); + $oPage->p("$count server(s) at this location:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('bizNetworkDevice'); + $oSearchFilter->AddCondition('location_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Network Devices"); + $oPage->p("$count Network Device(s) at this location:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('bizPC'); + $oSearchFilter->AddCondition('location_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("PCs"); + $oPage->p("$count PC(s) at this location:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('bizPerson'); + $oSearchFilter->AddCondition('location_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Contacts"); + $oPage->p("$count person(s) located to this location:"); + $this->DisplaySet($oPage, $oSet); + } + + $oSearchFilter = new CMDBSearchFilter('lnkDocumentRealObject'); + $oSearchFilter->AddCondition('object_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Details"); + $oPage->p("$count Document(s) linked to this location:"); + $this->DisplaySet($oPage, $oSet); + } +*/ + + } + + + public function Generate(cmdbDataGenerator $oGenerator) + { + parent::Generate($oGenerator); + $sLastName = $oGenerator->GenerateLastName(); + $sCityName = $oGenerator->GenerateCityName(); + $this->Set('name', $sCityName); + $this->Set('country', $oGenerator->GenerateCountryName()); + $this->Set('address', $oGenerator->GenerateString("number(1-999)| |enum(rue,rue,rue,place,avenue,av.,route de)| |$sLastName| |number(0000-9999)|0 |$sCityName")); + $this->Set('parent_location_id', 1); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Circuit (one end only) +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizCircuit extends logInfra +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Circuit", + "description" => "Any type of circuit", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "carrier_name", "carrier_ref", "name"), // inherited attributes + "db_table" => "circuits", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/Circuits.html", + ); + + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("speed", array("label"=>"speed", "description"=>"speed of the circuit", "allowed_values"=>null, "sql"=>"speed", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("location_id", array("targetclass"=>"bizLocation", "label"=>"Location ID", "description"=>"Id of the location", "allowed_values"=>null, "sql"=>"location_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("location_name", array("label"=>"Location", "description"=>"Name of the location", "allowed_values"=>null, "extkey_attcode"=> 'location_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("interface_id", array("targetclass"=>"bizInterface", "label"=>"Interface Id", "description"=>"id of the interface", "allowed_values"=>null, "sql"=>"interface_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface_name", array("label"=>"Interface", "description"=>"Name of the interface", "allowed_values"=>null, "extkey_attcode"=> 'interface_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("provider_id", array("targetclass"=>"bizOrganization", "label"=>"Carrier ID", "description"=>"Organization ID of the provider of the Circuit", "allowed_values"=>null, "sql"=>"provider_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("carrier_name", array("label"=>"Carrier", "description"=>"Name of the carrier", "allowed_values"=>null, "extkey_attcode"=> 'provider_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("carrier_ref", array("label"=>"Carrier reference", "description"=>"reference of the circuit used by the carrier", "allowed_values"=>null, "sql"=>"carrier_ref", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("speed"); + MetaModel::Init_AddFilterFromAttribute("location_id"); + MetaModel::Init_AddFilterFromAttribute("location_name"); + MetaModel::Init_AddFilterFromAttribute("interface_id"); + MetaModel::Init_AddFilterFromAttribute("provider_id"); + MetaModel::Init_AddFilterFromAttribute("carrier_ref"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'speed', 'provider_id', 'carrier_ref', 'location_id')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'org_id', 'provider_id', 'carrier_ref', 'speed')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'carrier_ref', 'speed', 'provider_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'carrier_ref', 'speed', 'provider_id')); // Criteria of the advanced search form + } + + public function ComputeValues() + { +/* + $oLocatedObject = MetaModel::GetObject("Located Object", $this->Get("located_object_id")); + + $this->Set("location_id", $oLocatedObject->Get("location_id")); + // Houston, I've got an issue, as this field is calculated, I should reload the object... + $this->Set("location_name", "abc (to be finalized)"); + + $this->Set("device_id", $oLocatedObject->Get("device_id")); + // Houston, I've got an issue, as this field is calculated, I should reload the object... + $this->Set("device_name", "abc (to be finalized)"); + + $this->Set("interface_id", $oLocatedObject->Get("interface_id")); + // Houston, I've got an issue, as this field is calculated, I should reload the object... + $this->Set("interface_name", "abc (to be finalized)"); +*/ + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Any Device Network Interface +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizInterface extends logInfra +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Interface", + "description" => "Interface", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "device_name", "name"), + "db_table" => "interfaces", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/interface.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalKey("device_id", array("targetclass"=>"bizDevice", "label"=>"Device", "description"=>"Device on which the interface is physically located", "allowed_values"=>null, "sql"=>"device_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("device_name", array("label"=>"Device", "description"=>"name of the device on which the interface is located", "allowed_values"=>null, "extkey_attcode"=> 'device_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("device_location_id", array("label"=>"Device location", "description"=>"location of the device on which the interface is located", "allowed_values"=>null, "extkey_attcode"=> 'device_id', "target_attcode"=>"location_id"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("device_location_name", array("label"=>"Device location", "description"=>"name of the location of the device on which the interface is located", "allowed_values"=>null, "extkey_attcode"=> 'device_id', "target_attcode"=>"location_name"))); + + MetaModel::Init_AddAttribute(new AttributeEnum("logical_type", array("label"=>"Logical type", "description"=>"Logical type of interface", "allowed_values"=>new ValueSetEnum("primary,secondary,backup,port,logical"), "sql"=>"logical_type", "default_value"=>"port", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("physical_type", array("label"=>"Physical type", "description"=>"Physical type of interface", "allowed_values"=>new ValueSetEnum("ethernet,framerelay,atm,vlan"), "sql"=>"physical_type", "default_value"=>"ethernet", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("ip_address", array("label"=>"IP address", "description"=>"address IP for this interface", "allowed_values"=>null, "sql"=>"ip_address", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("mask", array("label"=>"Subnet Mask", "description"=>"Subnet mask for this interface", "allowed_values"=>null, "sql"=>"mask", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("mac", array("label"=>"MAC address", "description"=>"MAC address for this interface", "allowed_values"=>null, "sql"=>"mac", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("speed", array("label"=>"Speed (Kb/s)", "description"=>"speed of this interface", "allowed_values"=>null, "sql"=>"speed", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeEnum("duplex", array("label"=>"Duplex", "description"=>"Duplex configured for this interface", "allowed_values"=>new ValueSetEnum("half,full,unknown"), "sql"=>"duplex", "default_value"=>"unknown", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("device_id"); + MetaModel::Init_AddFilterFromAttribute("device_name"); + MetaModel::Init_AddFilterFromAttribute("device_location_id"); + MetaModel::Init_AddFilterFromAttribute("logical_type"); + MetaModel::Init_AddFilterFromAttribute("physical_type"); + MetaModel::Init_AddFilterFromAttribute("ip_address"); + MetaModel::Init_AddFilterFromAttribute("mac"); + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'device_id', 'device_location_id','severity','logical_type','physical_type','ip_address','mask','mac','speed','duplex')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'org_id', 'device_id','severity')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'ip_address','mac','device_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'device_id', 'org_id')); // Criteria of the advanced search form + } + + function DisplayDetails(web_page $oPage) + { + parent::DisplayDetails($oPage); + /* + $oSearchFilter = new CMDBSearchFilter('lnkInterfaces'); + $oSearchFilter->AddCondition('interface1_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Connected interfaces"); + $oPage->p("$count interface(s) connected to this device:"); + $this->DisplaySet($oPage, $oSet); + } + */ + } + + public function ComputeValues() + { + /* + // my location is the location of my device + $oDevice = MetaModel::GetObject("bizDevice", $this->Get("device_id")); + $this->Set("location_id", $oDevice->Get("location_id")); + // Houston, I've got an issue, as this field is calculated, I should reload the object... + $this->Set("location_name", "abc (to be finalized)"); + + // my device is given by my Creator + + // my interface is myself + $this->Set("interface_id", $this->GetKey()); + // Houston, I've got an issue, as this field is calculated, I should reload the object... + $this->Set("interface_name", "abc (to be finalized)"); + */ + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Interfaces +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkInterfaces extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "InterfacesLinks", + "description" => "A link between two interfaces", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "link_type", + "state_attcode" => "", + "reconc_keys" => array("interface1_id", "interface2_id"), + "db_table" => "interfaces_links", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("interface1_id", array("targetclass"=>"bizInterface", "label"=>"Interface1", "description"=>"The interface1", "sql"=>"interface1_id", "allowed_values"=> null, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface1_name", array("label"=>"Interface1 name", "description"=>"name of the interface1", "extkey_attcode"=> 'interface1_id', "allowed_values"=> null, "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("interface2_id", array("targetclass"=>"bizInterface", "label"=>"Interface2", "description"=>"The interface2", "sql"=>"interface2_id", "allowed_values"=> null, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface2_name", array("label"=>"Interface2 name", "description"=>"name of the interface2", "extkey_attcode"=> 'interface2_id', "allowed_values"=> null, "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface1_device_id", array("label"=>"Device1", "description"=>"device", "extkey_attcode"=> 'interface1_id', "allowed_values"=> null, "target_attcode"=>"device_id"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface1_device_name", array("label"=>"Device name", "description"=>"name of the device", "extkey_attcode"=> 'interface1_id', "allowed_values"=> null, "target_attcode"=>"device_name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface2_device_id", array("label"=>"Device2", "description"=>"device", "extkey_attcode"=> 'interface2_id', "allowed_values"=> null, "target_attcode"=>"device_id"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("interface2_device_name", array("label"=>"Device name", "description"=>"name of the device", "extkey_attcode"=> 'interface2_id', "allowed_values"=> null, "target_attcode"=>"device_name"))); + MetaModel::Init_AddAttribute(new AttributeString("link_type", array("label"=>"link type", "description"=>" Definition of the link", "sql"=>"link_type", "default_value"=>"", "allowed_values"=> null, "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("interface1_id"); + MetaModel::Init_AddFilterFromAttribute("interface1_name"); + MetaModel::Init_AddFilterFromAttribute("interface2_id"); + MetaModel::Init_AddFilterFromAttribute("interface2_name"); + MetaModel::Init_AddFilterFromAttribute("interface2_device_name"); + MetaModel::Init_AddFilterFromAttribute("link_type"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('interface1_id', 'interface2_id', 'link_type')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('interface1_id', 'interface1_device_id', 'interface2_id', 'interface2_device_id', 'link_type')); // Attributes to be displayed for the complete details + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* Any electronic device +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizDevice extends logInfra +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Device", + "description" => "Electronic devices", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "devices", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalKey("location_id", array("targetclass"=>"bizLocation", "label"=>"Location", "description"=>"where is the located object physically located", "allowed_values"=>null, "sql"=>"location_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("location_name", array("label"=>"Location name", "description"=>"name of the location", "allowed_values"=>null, "extkey_attcode"=> 'location_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("country", array("label"=>"Country", "description"=>"country where the device is located", "allowed_values"=>null, "extkey_attcode"=> 'location_id', "target_attcode"=>"country"))); + MetaModel::Init_AddAttribute(new AttributeString("brand", array("label"=>"Brand", "description"=>"The manufacturer of the device", "allowed_values"=>null, "sql"=>"brand", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("model", array("label"=>"Model", "description"=>"The model number of the device", "allowed_values"=>null, "sql"=>"model", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("serial_number", array("label"=>"Serial Number", "description"=>"The serial number of the device", "allowed_values"=>null, "sql"=>"serial_number", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("location_id"); + MetaModel::Init_AddFilterFromAttribute("country"); + MetaModel::Init_AddFilterFromAttribute("brand"); + MetaModel::Init_AddFilterFromAttribute("model"); + MetaModel::Init_AddFilterFromAttribute("serial_number"); + } + + public static function GetRelationQueries($sRelCode) + { + switch ($sRelCode) + { + case "impacts": + $aRels = array( + "connected device" => array("sQuery"=>"bizDevice: PKEY IS device_id IN (bizInterface: PKEY IS interface2_id IN (lnkInterfaces: interface1_id IN (bizInterface: device_id = \$[this.pkey::])))", "bPropagate"=>true, "iDistance"=>3), + "hosted app" => array("sQuery"=>"bizApplication: infra_id = \$[this.pkey::]", "bPropagate"=>true, "iDistance"=>3), + ); + return array_merge($aRels, parent::GetRelationQueries($sRelCode)); + } + } + + public function ComputeValues() + { + /* + // my location is the location of my device (external field) + $this->Set("location_id", $this->Get("device_location_id")); + // Houston, I've got an issue, as this field is calculated, I should reload the object... + $this->Set("location_name", "abc (to be finalized)"); + + // my device is myself + $this->Set("device_id", $this->GetKey()); + + // my interface is "nothing" + $this->Set("interface_id", null); + */ + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* A personal computer +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizPC extends bizDevice +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "PC", + "description" => "Personal Computers", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "pcs", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/pc.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of computer", "allowed_values"=>new ValueSetEnum("desktop PC,laptop"), "sql"=>"type", "default_value"=>"desktop PC", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("memory_size", array("label"=>"Memory Size", "description"=>"Size of the memory", "allowed_values"=>null, "sql"=>"memory_size", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("cpu", array("label"=>"CPU", "description"=>"CPU type", "allowed_values"=>null, "sql"=>"cpu_type", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("hdd_size", array("label"=>"HDD Size", "description"=>"Size of the hard drive", "allowed_values"=>null, "sql"=>"hdd_size", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("os_family", array("label"=>"OS Family", "description"=>"Type of operating system", "allowed_values"=>null, "sql"=>"os_family", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("os_version", array("label"=>"OS Version", "description"=>"Detailed version number of the operating system", "allowed_values"=>null, "sql"=>"os_version", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("shipment_number", array("label"=>"Shipment number", "description"=>"Number for tracking shipment", "allowed_values"=>null, "sql"=>"shipment_number", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("mgmt_ip", array("label"=>"Mgmt IP", "description"=>"Management IP", "allowed_values"=>null, "sql"=>"mgmt_ip", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("default_gateway", array("label"=>"Default Gateway", "description"=>"Default Gateway for this device", "allowed_values"=>null, "sql"=>"default_gateway", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("type"); + MetaModel::Init_AddFilterFromAttribute("memory_size"); + MetaModel::Init_AddFilterFromAttribute("cpu"); + MetaModel::Init_AddFilterFromAttribute("hdd_size"); + MetaModel::Init_AddFilterFromAttribute("os_family"); + MetaModel::Init_AddFilterFromAttribute("os_version"); + MetaModel::Init_AddFilterFromAttribute("mgmt_ip"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status','severity', 'org_id', 'location_id', 'brand', 'model','os_family','os_version','mgmt_ip','default_gateway','shipment_number','serial_number', 'type', 'cpu', 'memory_size', 'hdd_size')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status', 'severity', 'org_id', 'location_id', 'brand', 'model', 'type')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'severity','type', 'brand', 'model','os_family','mgmt_ip')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'type', 'brand', 'model', 'cpu', 'memory_size', 'hdd_size')); // Criteria of the advanced search form + } + + function DisplayDetails(web_page $oPage) + { + parent::DisplayDetails($oPage); + /* + parent::DisplayDetails($oPage); + $oSearchFilter = new CMDBSearchFilter('lnkContactRealObject'); + $oSearchFilter->AddCondition('object_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Contacts"); + $oPage->p("$count contact(s) linked to this PC:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('bizInterface'); + $oSearchFilter->AddCondition('device_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Interfaces"); + $oPage->p("$count interface(s) for this device:"); + $this->DisplaySet($oPage, $oSet); + } + */ + } + + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('org_id', $oGenerator->GetOrganizationId()); + $this->Set('location_id', $oGenerator->GenerateKey("bizLocation", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('name', $oGenerator->GenerateString("enum(pc,pc,pc,pc,pc,win,redhat,linux,srv,workstation)|number(000-999)|.|domain()")); + $this->Set('brand', $oGenerator->GenerateString("enum(Hewlett-Packard,Dell,Compaq,Siemens,Packard Bell,IBM,Gateway,Medion,Sony)")); + $this->Set('model', $oGenerator->GenerateString("enum(Vectra,Deskpro,Dimension,Optiplex,Latitude,Precision,Vaio)")); + $this->Set('serial_number', $oGenerator->GenerateString("enum(FR,US,TW,CH)|number(000000-999999)")); + $this->Set('memory_size', $oGenerator->GenerateString("enum(128,256,384,512,768,1024,1536,2048)")); + $this->Set('cpu', $oGenerator->GenerateString("enum(Pentium III,Pentium 4, Pentium M,Core Duo,Core 2 Duo,Celeron,Opteron,Thurion,Athlon)")); + $this->Set('hdd_size', $oGenerator->GenerateString("enum(40,60,80,120,200,300)")); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* A server +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizServer extends bizDevice +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Server", + "description" => "Computer Servers", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "status", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "servers", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/server.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeEnum("status", array("label"=>"Status", "description"=>"Status of the server", "allowed_values"=>new ValueSetEnum("In Store,Shipped,Plugged,Production Candidate,In Production,In Change,Being Deconfigured,Obsolete"), "sql"=>"status", "default_value"=>"In Store", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("memory_size", array("label"=>"Memory Size", "description"=>"Size of the memory", "allowed_values"=>null, "sql"=>"memory_size", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("cpu", array("label"=>"Model", "description"=>"CPU type", "allowed_values"=>null, "sql"=>"cpu_type", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("number_of_cpus", array("label"=>"Number of CPUs", "description"=>"Number of CPUs", "allowed_values"=>null, "sql"=>"number_of_cpus", "default_value"=>"1", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("hdd_size", array("label"=>"HDD Size", "description"=>"Size of the hard drive", "allowed_values"=>null, "sql"=>"hdd_size", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("hdd_free_size", array("label"=>"Free HDD Size", "description"=>"Size of the free space on the hard drive(s)", "allowed_values"=>null, "sql"=>"hdd_free_size", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("os_family", array("label"=>"OS Family", "description"=>"Type of operating system", "allowed_values"=>null, "sql"=>"os_family", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("os_version", array("label"=>"OS Version", "description"=>"Detailed version number of the operating system", "allowed_values"=>null, "sql"=>"os_version", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("shipment_number", array("label"=>"Shipment number", "description"=>"Number for tracking shipment", "allowed_values"=>null, "sql"=>"shipment_number", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("mgmt_ip", array("label"=>"Mgmt IP", "description"=>"Management IP", "allowed_values"=>null, "sql"=>"mgmt_ip", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("default_gateway", array("label"=>"Default Gateway", "description"=>"Default Gateway for this device", "allowed_values"=>null, "sql"=>"default_gateway", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("memory_size"); + MetaModel::Init_AddFilterFromAttribute("cpu"); + MetaModel::Init_AddFilterFromAttribute("number_of_cpus"); + MetaModel::Init_AddFilterFromAttribute("hdd_size"); + MetaModel::Init_AddFilterFromAttribute("hdd_free_size"); + MetaModel::Init_AddFilterFromAttribute("os_family"); + MetaModel::Init_AddFilterFromAttribute("os_version"); + + + // Life cycle + MetaModel::Init_DefineState("In Store", array("label"=>"InStore", "description"=>"Device in store", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Shipped", array("label"=>"Shipped", "description"=>"The device had been shipped to future location", "attribute_inherit"=>null, + "attribute_list"=>array("location_id"=>OPT_ATT_MANDATORY,"serial_number"=>OPT_ATT_MANDATORY,"shipment_number"=>OPT_ATT_MANDATORY))); + MetaModel::Init_DefineState("Plugged", array("label"=>"Plugged", "description"=>"The device is connected to the network", "attribute_inherit"=>null, + "attribute_list"=>array("location_id"=>OPT_ATT_MANDATORY,"mgmt_ip"=>OPT_ATT_MANDATORY,"name"=>OPT_ATT_MANDATORY))); + MetaModel::Init_DefineState("Production Candidate", array("label"=>"Pre-Production", "description"=>"The device is ready to be move to production", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("In Production", array("label"=>"Production", "description"=>"The device is on production", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("In Change", array("label"=>"InChange", "description"=>"A change is being performed on the device", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Being Deconfigured", array("label"=>"BeingDeconfigured", "description"=>"The device is about to be removed from is current location", "attribute_inherit"=>null, + "attribute_list"=>array())); + MetaModel::Init_DefineState("Obsolete", array("label"=>"Obsolete", "description"=>"The device is no more used", "attribute_inherit"=>null, + "attribute_list"=>array())); + + + MetaModel::Init_DefineStimulus("ev_store", new StimulusUserAction(array("label"=>"Store this server", "description"=>"This server is move to storage"))); + MetaModel::Init_DefineStimulus("ev_ship", new StimulusUserAction(array("label"=>"Ship this server", "description"=>"This server is shipped to futur location"))); + MetaModel::Init_DefineStimulus("ev_plug", new StimulusUserAction(array("label"=>"Plug this server", "description"=>"The server is pluuged on the network"))); + MetaModel::Init_DefineStimulus("ev_configuration_finished", new StimulusUserAction(array("label"=>"Configuration finished", "description"=>"The device is ready to move to production evaluation"))); + MetaModel::Init_DefineStimulus("ev_val_failed", new StimulusUserAction(array("label"=>"Review configuration", "description"=>"The configuration for this server is not completed"))); + MetaModel::Init_DefineStimulus("ev_mtp", new StimulusUserAction(array("label"=>"Move to Production", "description"=>"The server is moved to production"))); + MetaModel::Init_DefineStimulus("ev_start_change", new StimulusUserAction(array("label"=>"Change Start [No Click]", "description"=>"A change starts for this server"))); + MetaModel::Init_DefineStimulus("ev_end_change", new StimulusUserAction(array("label"=>"End Change [No Click]", "description"=>"No more change running for this server"))); + MetaModel::Init_DefineStimulus("ev_decommission", new StimulusUserAction(array("label"=>"Decommission", "description"=>"The server is being decommissioned"))); + MetaModel::Init_DefineStimulus("ev_obsolete", new StimulusUserAction(array("label"=>"Obsolete", "description"=>"The server is no more used"))); + MetaModel::Init_DefineStimulus("ev_recycle", new StimulusUserAction(array("label"=>"Recycle this server", "description"=>"The server is move back to deconfiguration"))); + + MetaModel::Init_DefineTransition("In Store", "ev_ship", array("target_state"=>"Shipped", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("In Store", "ev_plug", array("target_state"=>"Plugged", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Shipped", "ev_store", array("target_state"=>"In Store", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Shipped", "ev_plug", array("target_state"=>"Plugged", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Plugged", "ev_ship", array("target_state"=>"Shipped", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Plugged", "ev_store", array("target_state"=>"In Store", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Plugged", "ev_configuration_finished", array("target_state"=>"Production Candidate", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Production Candidate", "ev_val_failed", array("target_state"=>"Plugged", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Production Candidate", "ev_mtp", array("target_state"=>"In Production", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("In Production", "ev_start_change", array("target_state"=>"In Change", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("In Production", "ev_obsolete", array("target_state"=>"Obsolete", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("In Production", "ev_decommission", array("target_state"=>"Being Deconfigured", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("In Change", "ev_end_change", array("target_state"=>"In Production", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Being Deconfigured", "ev_ship", array("target_state"=>"Shipped", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Being Deconfigured", "ev_plug", array("target_state"=>"Plugged", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Being Deconfigured", "ev_store", array("target_state"=>"In Store", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Being Deconfigured", "ev_obsolete", array("target_state"=>"Obsolete", "actions"=>array(), "user_restriction"=>null)); + MetaModel::Init_DefineTransition("Obsolete", "ev_recycle", array("target_state"=>"Being Deconfigured", "actions"=>array(), "user_restriction"=>null)); + + + + + + // Display lists + + MetaModel::Init_SetZListItems('details', array('name', 'mgmt_ip','default_gateway','status', 'severity','org_id', 'location_id', 'brand', 'model', 'os_family', 'os_version','serial_number','shipment_number', 'cpu', 'number_of_cpus', 'memory_size', 'hdd_size', 'hdd_free_size')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status','severity', 'org_id', 'location_id', 'brand', 'model', 'os_family', 'os_version')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status','severity', 'brand', 'model', 'os_family', 'location_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status','brand', 'model', 'os_family', 'os_version', 'location_id', 'cpu', 'number_of_cpu', 'memory_size', 'hdd_size', 'hdd_free_size')); // Criteria of the advanced search form + } + + function DisplayDetails(web_page $oPage) + { + parent::DisplayDetails($oPage); + /* + parent::DisplayDetails($oPage); + $oSearchFilter = new CMDBSearchFilter('lnkContactRealObject'); + $oSearchFilter->AddCondition('object_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Contacts"); + $oPage->p("$count contact(s) for this server:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('bizInterface'); + $oSearchFilter->AddCondition('device_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Interfaces"); + $oPage->p("$count interface(s) for this server:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('Application'); + $oSearchFilter->AddCondition('infra_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Installed applications"); + $oPage->p("$count application(s) installed on this server:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('bizPatch'); + $oSearchFilter->AddCondition('infra_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Installed patches"); + $oPage->p("$count patch(s) installed on this server:"); + $this->DisplaySet($oPage, $oSet); + } + */ + + + } + + + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('org_id', $oGenerator->GetOrganizationId()); + $this->Set('location_id', $oGenerator->GenerateKey("bizLocation", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('name', $oGenerator->GenerateString("enum(pc,pc,pc,pc,pc,win,redhat,linux,srv,workstation)|number(000-999)|.|domain()")); + $this->Set('brand', $oGenerator->GenerateString("enum(Hewlett-Packard,Dell,Compaq,Siemens,Packard Bell,IBM,Gateway,Medion,Sony)")); + $this->Set('model', $oGenerator->GenerateString("enum(Vectra,Deskpro,Dimension,Optiplex,Latitude,Precision,Vaio)")); + $this->Set('serial_number', $oGenerator->GenerateString("enum(FR,US,TW,CH)|number(000000-999999)")); + $this->Set('memory_size', $oGenerator->GenerateString("enum(512,1024,2048,4096,2048,4096,8192,8192,8192,16384,32768)")); + $this->Set('cpu', $oGenerator->GenerateString("enum(Pentium III,Pentium 4,Pentium M,Core Duo,Core 2 Duo,Celeron,Opteron,Thurion,Athlon)")); + $this->Set('number_of_cpu', $oGenerator->GenerateString("enum(1,1,2,2,2,2,2,4,4,8)")); + $this->Set('hdd_size', $oGenerator->GenerateString("enum(500,1024,500,1024,500,1024,2048)")); + $this->Set('hdd_free_size', $this->Get('hdd_size')*$oGenerator->GenerateString("number(20-80)")); + $this->Set('os_family', $oGenerator->GenerateString("enum(Windows,Windows,Windows,Linux,Windows,Linux,Windows,Linux,Linux,HP-UX,Solaris,AIX)")); + $this->Set('os_version', $oGenerator->GenerateString("enum(XP,XP,XP,RH EL 4,RH EL 5,SuSE 10.3,SuSE 10.4,11.11,11.11i)")); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* A network device +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizNetworkDevice extends bizDevice +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Network Device", + "description" => "A network device", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "network_devices", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/network.device.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of device", "allowed_values"=>new ValueSetEnum("switch,router,firewall,load balancer,hub,WAN accelerator"), "sql"=>"type", "default_value"=>"switch", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("ip_address", array("label"=>"Mgmt IP", "description"=>"Management IP address", "allowed_values"=>null, "sql"=>"ip_address", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("default_gateway", array("label"=>"Default Gateway", "description"=>"Default Gateway for this device", "allowed_values"=>null, "sql"=>"default_gateway", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("ios_version", array("label"=>"IOS version", "description"=>"IOS (software) version", "allowed_values"=>null, "sql"=>"ios_version", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("memory", array("label"=>"Memory", "description"=>"Memory description", "allowed_values"=>null, "sql"=>"memory", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeString("snmp_read", array("label"=>"SNMP Community (Read)", "description"=>"SNMP Read Community String", "allowed_values"=>null, "sql"=>"snmp_read", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("snmp_write", array("label"=>"SNMP Community (Write)", "description"=>"SNMP Write Community String", "allowed_values"=>null, "sql"=>"snmp_write", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("type"); + MetaModel::Init_AddFilterFromAttribute("ip_address"); + MetaModel::Init_AddFilterFromAttribute("ios_version"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status','severity','org_id', 'location_id', 'brand','model','type','ip_address','default_gateway','serial_number','ios_version','memory','snmp_read','snmp_write')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name', 'status','brand','model','type','ip_address')); // Attributes to be displayed for a list + + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'location_id', 'brand','model','type','ip_address')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id', 'location_id', 'brand','model','type','ip_address','serial_number','ios_version','snmp_read','snmp_write')); // Criteria of the advanced search form + + + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('org_id', $oGenerator->GetOrganizationId()); + $this->Set('location_id', $oGenerator->GenerateKey("bizLocation", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('name', $oGenerator->GenerateString("enum(sw,swi,switch,rout,rtr,gw)|number(000-999)|.|domain()")); + $this->Set('brand', $oGenerator->GenerateString("enum(Hewlett-Packard,Cisco,3Com,Avaya,Alcatel,Cabletron,Extrem Networks,Juniper,Netgear,Synopitcs,Xylan)")); + $this->Set('model', $oGenerator->GenerateString("enum(Procurve ,Catalyst ,Multiswitch ,C)|enum(25,26,36,40,65)|enum(00,09,10,50)")); + $this->Set('serial_number', $oGenerator->GenerateString("enum(FAA,AGA,PAD,COB,DFE)|number(0000-9999)|enum(M,X,L)")); + $this->Set('ip_address', $oGenerator->GenerateString("number(10-248)|.|number(1-254)|.|number(1-254)|.|number(1-254)")); + $this->Set('ios_version', $oGenerator->GenerateString("enum(9,10,12)|.|enum(0,1,2)|enum(,,,,XP,.5.1)")); + $this->Set('snmp_read', $oGenerator->GenerateString("enum(Ew,+0,**,Ps)|number(00-99)|enum(+,=,],;, )|enum(Aze,Vbn,Bbn,+9+,-9-,#)")); + $this->Set('snmp_write', $oGenerator->GenerateString("enum(M3,l3,$,*,Zz,Ks,jh)|number(00-99)|enum(A*e,V%n,Bbn,+,-,#)|number(0-9)")); + } +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* A "Solution" +*/ +//////////////////////////////////////////////////////////////////////////////////// +class bizInfraGroup extends logInfra +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Infra Group", + "description" => "A group of infrastructure elements", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("org_name", "name"), // inherited attributes + "db_table" => "infra_group", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/group.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeEnum("type", array("label"=>"Type", "description"=>"Type of groupe", "allowed_values"=>new ValueSetEnum("Monitoring,Reporting,list"), "sql"=>"type", "default_value"=>"list", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("description", array("label"=>"Description", "description"=>"usage of the Group", "allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("parent_group_id", array("targetclass"=>"bizInfraGroup", "label"=>"Parent Group", "description"=>"including group", "allowed_values"=>null, "sql"=>"parent_group_id", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("parent_group_name", array("label"=>"Parent Group (Name)", "description"=>"name of the parent group", "allowed_values"=>null, "extkey_attcode"=> 'parent_group_id', "target_attcode"=>"name"))); + + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("type"); + MetaModel::Init_AddFilterFromAttribute("parent_group_id"); + MetaModel::Init_AddFilterFromAttribute("parent_group_name"); + + + // Display lists + MetaModel::Init_SetZListItems('details', array('name', 'status', 'org_id', 'type', 'description','parent_group_id')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('name', 'status', 'org_id', 'type', 'description')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'type')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'type', 'description', 'org_id')); // Criteria of the advanced search form + } + + function DisplayDetails(web_page $oPage) + { + parent::DisplayDetails($oPage); + /* + $oSearchFilter = new CMDBSearchFilter('lnkInfraGrouping'); + $oSearchFilter->AddCondition('infra_group_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("RelatedInfrastructure"); + $oPage->p("Infrastructure Link to this group:"); + $this->DisplaySet($oPage, $oSet); + } + $oSearchFilter = new CMDBSearchFilter('lnkContactRealObject'); + $oSearchFilter->AddCondition('object_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("TeamLinks"); + $oPage->p("People concerned by this group:"); + $this->DisplaySet($oPage, $oSet); + } +*/ + } + + + + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('org_id', $oGenerator->GetOrganizationId()); + $this->Set('name', $oGenerator->GenerateString("enum(ov_nnm_,ovpi_,vitalnet_,datacenter_,web_farm_)|number(000-999)")); + $this->Set('type', $oGenerator->GenerateString("enum(Application,Infrastructure)")); + } +} +//////////////////////////////////////////////////////////////////////////////////// +//** +//* An application is an instance of a software install on a PC or Server +//* +//////////////////////////////////////////////////////////////////////////////////// +class bizApplication extends logInfra +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Application", + "description" => "General application", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("device_name", "name"), // inherited attributes + "db_table" => "applications", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/application.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalKey("device_id", array("targetclass"=>"bizDevice", "jointype"=> '', "label"=>"Hosting device", "description"=>"The device where application is installed", "allowed_values"=>null, "sql"=>"device_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("device_name", array("label"=>"Hosting device", "description"=>"Name of the device where application is installed", "allowed_values"=>null, "extkey_attcode"=> 'device_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeDate("install_date", array("label"=>"Installed date", "description"=>"Date when application was installed", "allowed_values"=>null, "sql"=>"install_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeString("version", array("label"=>"Version", "description"=>"Application version", "allowed_values"=>null, "sql"=>"version", "default_value"=>"undefined", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("function", array("label"=>"Function", "description"=>"Function provided by this application", "allowed_values"=>null, "sql"=>"function", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("function"); + MetaModel::Init_AddFilterFromAttribute("version"); + MetaModel::Init_AddFilterFromAttribute("device_id"); + + + + + // Display lists + MetaModel::Init_SetZListItems('details', array('name','device_id','org_id','status','install_date', 'version','function')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name','device_id', 'version', 'function')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'device_id','version','function')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'device_id','version','function')); // Criteria of the advanced search form + + } + + public static function GetRelationQueries($sRelCode) + { + switch ($sRelCode) + { + case "impacts": + $aRels = array( + "client app" => array("sQuery"=>"bizApplication: PKEY IS client_id IN (lnkClientServer: server_id = \$[this.pkey::])", "bPropagate"=>true, "iDistance"=>3), + ); + return array_merge($aRels, parent::GetRelationQueries($sRelCode)); + } + } + + function DisplayDetails(web_page $oPage) + { + parent::DisplayDetails($oPage); + /* + $oSearchFilter = new CMDBSearchFilter('lnkClientServer'); + $oSearchFilter->AddCondition('server_id', $this->GetKey(), '='); + $oSet = new CMDBObjectSet($oSearchFilter); + $count = $oSet->Count(); + if ($count > 0) + { + $oPage->SetCurrentTab("Connected clients"); + $oPage->p("Client applications impacted when down:"); + $this->DisplaySet($oPage, $oSet); + } +*/ + } + +} + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between any Infra and a Group +*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkInfraGrouping extends cmdbAbstractObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Infra Grouping", + "description" => "Infra part of an Infra Group", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "impact", + "state_attcode" => "", + "reconc_keys" => array(""), + "db_table" => "infra_grouping", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("infra_id", array("targetclass"=>"logInfra", "jointype"=> '', "label"=>"Infrastructure", "description"=>"Infrastructure part of the group", "allowed_values"=>null, "sql"=>"infra_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_name", array("label"=>"Infrastructure name", "description"=>"Name of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("infra_status", array("label"=>"Status", "description"=>"Status of the impacted infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_id', "target_attcode"=>"status"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("infra_group_id", array("targetclass"=>"bizInfraGroup", "jointype"=> '', "label"=>"Group Name", "description"=>"Name of the group", "allowed_values"=>null, "sql"=>"infra_group_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("group_name", array("label"=>"Group name", "description"=>"Name of the group containing infrastructure", "allowed_values"=>null, "extkey_attcode"=> 'infra_group_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("impact", array("label"=>"Relation", "description"=>"Relation between this group and infra", "allowed_values"=>null, "sql"=>"impact", "default_value"=>"none", "is_null_allowed"=>true, "depends_on"=>array()))); + // impact should modelized: enum (eg: if the group si dead when infra is dead) + + MetaModel::Init_AddFilterFromAttribute("infra_id"); + MetaModel::Init_AddFilterFromAttribute("infra_group_id"); + MetaModel::Init_AddFilterFromAttribute("impact"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('infra_id','infra_status', 'impact', 'infra_group_id')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('infra_id','infra_status', 'impact', 'infra_group_id')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('infra_id', 'infra_group_id', 'impact')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('infra_id', 'infra_group_id', 'impact')); // Criteria of the advanced search form + } + + public function Generate(cmdbDataGenerator $oGenerator) + { + $this->Set('infra_id', $oGenerator->GenerateKey("logInfra", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('infra_group_id', $oGenerator->GenerateKey("bizInfraGroup", array('org_id' =>$oGenerator->GetOrganizationId() ))); + $this->Set('impact', $oGenerator->GenerateString("enum(none,mandatory,partial)")); + } + +} + + + + + + +//////////////////////////////////////////////////////////////////////////////////// +/** +* n-n link between two applications, one is the server side and the scond one the client*/ +//////////////////////////////////////////////////////////////////////////////////// +class lnkClientServer extends logRealObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "ClientServerLinks", + "description" => "Link between client server application", + "key_type" => "autoincrement", + "key_label" => "link_id", + "name_attcode" => "relation", // ???? + "state_attcode" => "", + "reconc_keys" => array("relation"), // ???? + "db_table" => "clientserver_links", + "db_key_field" => "link_id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_AddAttribute(new AttributeExternalKey("client_id", array("targetclass"=>"bizApplication", "jointype"=> '', "label"=>"Client", "description"=>"The client part of the link", "allowed_values"=>null, "sql"=>"client_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("client_name", array("label"=>"Client", "description"=>"Name of the client", "allowed_values"=>null, "extkey_attcode"=> 'client_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("server_id", array("targetclass"=>"bizApplication", "jointype"=> '', "label"=>"Server", "description"=>"the server part of the link", "allowed_values"=>null, "sql"=>"server_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("server_name", array("label"=>"Server", "description"=>"Name of the server", "allowed_values"=>null, "extkey_attcode"=> 'server_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeString("relation", array("label"=>"Relation", "description"=>"Type of relation between both application", "allowed_values"=>null, "sql"=>"relation", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("client_id"); + MetaModel::Init_AddFilterFromAttribute("server_id"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('client_id', 'server_id', 'relation')); // Attributes to be displayed for a list + MetaModel::Init_SetZListItems('list', array('client_id', 'server_id', 'relation')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('client_id', 'server_id')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('client_id', 'server_id')); // Criteria of the advanced search form + } + + +} + +//////////////////////////////////////////////////////////////////////////////////// +//** +//* A patch is an application or OS fixe for an infrastructure +//* +//////////////////////////////////////////////////////////////////////////////////// +class bizPatch extends logRealObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "bizmodel,searchable", + "name" => "Patch", + "description" => "Patch installed on infrastucture", + "key_type" => "", + "key_label" => "id", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array("device_name", "name"), // inherited attributes + "db_table" => "patches", + "db_key_field" => "id", + "db_finalclass_field" => "", + "display_template" => "../business/templates/default.html", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalKey("device_id", array("targetclass"=>"bizDevice", "jointype"=> '', "label"=>"Device", "description"=>"The Device where patch is installed", "allowed_values"=>null, "sql"=>"device_id", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("device_name", array("label"=>"Device name", "description"=>"Name of the impacted device", "allowed_values"=>null, "extkey_attcode"=> 'device_id', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeDate("install_date", array("label"=>"Installed date", "description"=>"Date when application was installed", "allowed_values"=>null, "sql"=>"install_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddAttribute(new AttributeString("description", array("label"=>"Description", "description"=>"description du patch", "allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("patch_type", array("label"=>"Type", "description"=>"type de patch", "allowed_values"=>new ValueSetEnum("OS,Application"), "sql"=>"patch_type", "default_value"=>"OS", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + + MetaModel::Init_AddFilterFromAttribute("patch_type"); + MetaModel::Init_AddFilterFromAttribute("device_id"); + + + + + // Display lists + MetaModel::Init_SetZListItems('details', array('name','device_id', 'install_date', 'patch_type','description')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('name','device_id', 'patch_type','install_date')); // Attributes to be displayed for a list + // Search criteria + MetaModel::Init_SetZListItems('standard_search', array('name', 'device_id','patch_type')); // Criteria of the std search form + MetaModel::Init_SetZListItems('advanced_search', array('name', 'device_id','patch_type')); // Criteria of the advanced search form + + } +} + +/*** Insert here all modules requires for ITOP application ***/ + +require_once('incident.business.php'); +require_once('ServiceMgmt.business.php'); +require_once('ChangeMgmt.php'); +require_once('KEDB.php') +?> diff --git a/business/templates/Circuits.html b/business/templates/Circuits.html new file mode 100644 index 000000000..baafaf7f0 --- /dev/null +++ b/business/templates/Circuits.html @@ -0,0 +1,12 @@ + + +$class$: pkey = $pkey$ + + + bizInterface: PKEY IS interface_id IN (bizCircuit: pkey = $pkey$) + + diff --git a/business/templates/application.html b/business/templates/application.html new file mode 100644 index 000000000..49d34b51a --- /dev/null +++ b/business/templates/application.html @@ -0,0 +1,19 @@ + + +bizApplication: pkey = $pkey$ + + + bizApplication: PKEY IS client_id IN (lnkClientServer: server_id = $pkey$) + + + bizApplication: PKEY IS server_id IN (lnkClientServer: client_id = $pkey$) + + + lnkInfraContract: infra_id = $pkey$ + + + diff --git a/business/templates/change.html b/business/templates/change.html new file mode 100644 index 000000000..79d97aec5 --- /dev/null +++ b/business/templates/change.html @@ -0,0 +1,17 @@ + + +$class$: pkey = $pkey$ + + + lnkInfraChangeTicket: ticket_id = $pkey$ + + + lnkContactChange: change_id = $pkey$ + + + +
diff --git a/business/templates/contract.html b/business/templates/contract.html new file mode 100644 index 000000000..4ddcf760e --- /dev/null +++ b/business/templates/contract.html @@ -0,0 +1,18 @@ + + +bizContract: pkey = $pkey$ + + + lnkInfraContract: contract_id = $pkey$ + + + lnkContactContract: contract_id = $pkey$ + + + lnkDocumentContract: contract_id = $pkey$ + + diff --git a/business/templates/default.html b/business/templates/default.html new file mode 100644 index 000000000..d646d913c --- /dev/null +++ b/business/templates/default.html @@ -0,0 +1,8 @@ + + +$class$: pkey = $pkey$ + diff --git a/business/templates/document.html b/business/templates/document.html new file mode 100644 index 000000000..0125b8b2c --- /dev/null +++ b/business/templates/document.html @@ -0,0 +1,13 @@ + + +$class$: pkey = $pkey$ + + + bizDocVersion: document = $pkey$ + + + diff --git a/business/templates/group.html b/business/templates/group.html new file mode 100644 index 000000000..8e51d5995 --- /dev/null +++ b/business/templates/group.html @@ -0,0 +1,16 @@ + + +bizInfraGroup: pkey = $pkey$ + + + lnkInfraGrouping: infra_group_id = $pkey$ + + + lnkContactRealObject: object_id = $pkey$ + + + diff --git a/business/templates/interface.html b/business/templates/interface.html new file mode 100644 index 000000000..e59c4648f --- /dev/null +++ b/business/templates/interface.html @@ -0,0 +1,14 @@ + + +bizInterface: pkey = $pkey$ + + + lnkInterfaces: interface1_id = $pkey$ + lnkInterfaces: interface2_id = $pkey$ + + + diff --git a/business/templates/location.html b/business/templates/location.html new file mode 100644 index 000000000..28b13175e --- /dev/null +++ b/business/templates/location.html @@ -0,0 +1,25 @@ + + +bizLocation: pkey = $pkey$ + + + bizContact: location_id = $pkey$ + + + bizServer: location_id = $pkey$ + + + bizPC: location_id = $pkey$ + + + bizNetworkDevice: location_id = $pkey$ + + + + lnkDocumentRealObject: object_id = $pkey$ + + diff --git a/business/templates/network.device.html b/business/templates/network.device.html new file mode 100644 index 000000000..d9e2335d2 --- /dev/null +++ b/business/templates/network.device.html @@ -0,0 +1,20 @@ + + +bizNetworkDevice: pkey = $pkey$ + + + bizInterface: device_id = $pkey$ + + + bizContact: PKEY IS contact_id IN (lnkContactRealObject: object_id = $pkey$) + + + + lnkDocumentRealObject: object_id = $pkey$ + + + diff --git a/business/templates/pc.html b/business/templates/pc.html new file mode 100644 index 000000000..4b4a39a7d --- /dev/null +++ b/business/templates/pc.html @@ -0,0 +1,24 @@ + + +bizPC: pkey = $pkey$ + + + bizApplication: device_id = $pkey$ + + + bizPatch: device_id = $pkey$ + + + lnkContactRealObject: object_id = $pkey$ + + + bizInterface: device_id = $pkey$ + + + bizDocument: PKEY IS doc_id IN (lnkDocumentRealObject: object_id = $pkey$) + + diff --git a/business/templates/person.html b/business/templates/person.html new file mode 100644 index 000000000..e1e73c93a --- /dev/null +++ b/business/templates/person.html @@ -0,0 +1,18 @@ + + +bizPerson: pkey = $pkey$ + + + lnkContactRealObject: object_id = $pkey$ + + + logRealObject: PKEY IS object_id IN (lnkContactRealObject: contact_id = $pkey$) + + + bizDocument: PKEY IS doc_id IN (lnkDocumentRealObject: object_id = $pkey$) + + diff --git a/business/templates/server.html b/business/templates/server.html new file mode 100644 index 000000000..dc1fb09e6 --- /dev/null +++ b/business/templates/server.html @@ -0,0 +1,24 @@ + + +bizServer: pkey = $pkey$ + + + bizApplication: device_id = $pkey$ + + + bizPatch: device_id = $pkey$ + + + bizInterface: device_id = $pkey$ + + + lnkContactRealObject: object_id = $pkey$ + + + bizDocument: PKEY IS doc_id IN (lnkDocumentRealObject: object_id = $pkey$) + + diff --git a/business/templates/service.html b/business/templates/service.html new file mode 100644 index 000000000..c75444ac9 --- /dev/null +++ b/business/templates/service.html @@ -0,0 +1,13 @@ + + +$class$: pkey = $pkey$ + + + bizContract: service_id = $pkey$ + + + diff --git a/business/templates/software.html b/business/templates/software.html new file mode 100644 index 000000000..3c4ee0a18 --- /dev/null +++ b/business/templates/software.html @@ -0,0 +1,13 @@ + + +bizSoftware: pkey = $pkey$ + + + bizApplication: soft_id = $pkey$ + + + diff --git a/business/templates/team.html b/business/templates/team.html new file mode 100644 index 000000000..006cd5fba --- /dev/null +++ b/business/templates/team.html @@ -0,0 +1,21 @@ + + +$class$: pkey = $pkey$ + + + bizContact: PKEY IS object_id IN (lnkContactRealObject: contact_id = $pkey$) + + + bizTeam: PKEY IS object_id IN (lnkContactRealObject: contact_id = $pkey$) + + + logInfra: PKEY IS object_id IN (lnkContactRealObject: contact_id = $pkey$) + + + bizDocument: PKEY IS doc_id IN (lnkDocumentRealObject: object_id = $pkey$) + + diff --git a/business/templates/ticket.html b/business/templates/ticket.html new file mode 100644 index 000000000..645788e6f --- /dev/null +++ b/business/templates/ticket.html @@ -0,0 +1,21 @@ + + +$class$: pkey = $pkey$ + + + logInfra: PKEY IS infra_id IN (lnkInfraTicket: ticket_id = $pkey$) + + + lnkRelatedTicket: ticket_id = $pkey$ + + + lnkContactTicket: ticket_id = $pkey$ + + + + +
diff --git a/business/test_farm.class.inc.php b/business/test_farm.class.inc.php new file mode 100644 index 000000000..f3b240f98 --- /dev/null +++ b/business/test_farm.class.inc.php @@ -0,0 +1,272 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +/////////////////////////////////////////////////////////////////////////////// +// Business implementation demo +/////////////////////////////////////////////////////////////////////////////// + +//todo MetaModel::RegisterRelation("Potes", array("description"=>"ceux dont l'email ressemble au mien", "verb_down"=>"est pote de", "verb_up"=>"est pote de")); + + +//todo MetaModel::RegisterZList("list1", array("description"=>"une premiere list, just for fun", "type"=>"attributes")); +//todo MetaModel::RegisterZList("list2", array("description"=>"la secunda e meliora", "type"=>"attributes")); +//todo MetaModel::RegisterZList("list3", array("description"=>"la variante qui tue", "type"=>"filters")); + + +class Animal extends dbObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Animal", + "description" => "An animal", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(""), + "db_table" => "animals", + "db_key_field" => "animalid", + "db_finalclass_field" => "actualclass", + ); + MetaModel::Init_Params($aParams); + + MetaModel::Init_AddAttribute(new AttributeEnum("sex", array("label"=>"sex", "description"=>"sex", "allowed_values"=>new ValueSetEnum('male, female'), "sql"=>"sex", "default_value"=>"male", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("species", array("label"=>"species", "description"=>"species", "allowed_values"=>null, "sql"=>"species", "default_value"=>"xxx", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("speed", array("label"=>"walk speed", "description"=>"maximum possible speed m.s-1", "allowed_values"=>null, "sql"=>"speed", "default_value"=>4, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("mother", array("label"=>"mother", "description"=>"mother", "allowed_values"=>null, "sql"=>"mother", "targetclass"=>"Animal", "is_null_allowed"=>true, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("father", array("label"=>"father", "description"=>"father", "allowed_values"=>null, "sql"=>"father", "targetclass"=>"Animal", "is_null_allowed"=>true, "depends_on"=>array()))); + + //MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("sex"); + MetaModel::Init_AddFilterFromAttribute("species"); + MetaModel::Init_AddFilterFromAttribute("speed"); + MetaModel::Init_AddFilterFromAttribute("mother"); + MetaModel::Init_AddFilterFromAttribute("father"); + } +} + + +class Mammal extends Animal +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Mammal", + "description" => "An animal with some characteristics", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "mammals", + "db_key_field" => "mammalid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"name", "description"=>"name", "allowed_values"=>null, "sql"=>"name", "default_value"=>"xxx", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeInteger("height", array("label"=>"height", "description"=>"size in centimeters", "allowed_values"=>null, "sql"=>"height", "default_value"=>1, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeDate("birth", array("label"=>"birth date", "description"=>"birth date", "allowed_values"=>null, "sql"=>"birth", "default_value"=>1, "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("member", array("label"=>"member", "description"=>"leader", "allowed_values"=>null, "sql"=>"member", "targetclass"=>"Group", "is_null_allowed"=>true, "depends_on"=>array()))); + +// ? MetaModel::Init_AddAttribute(new AttributeLinkedSet("a2a", array("label"=>"animal to animal", "description"=>"interanimal relations", "depends_on"=>array(), "linked_class"=>"Animal2animal", "ext_key_to_me"=>"animal1", "count_min"=>0, "count_max"=>10, "allowed_values"=>null))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("height"); + MetaModel::Init_AddFilterFromAttribute("birth"); + MetaModel::Init_AddFilterFromAttribute("member"); + } +} + +class Bird extends Animal +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Bird", + "description" => "Un regroupement de gens", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "birds", + "db_key_field" => "birdid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_OverloadAttributeParams("species", array("allowed_values"=>array('geese', 'rooster', 'chicken', 'turckey', 'pie', 'corbeau'))); + + MetaModel::Init_InheritFilters(); + } +} + +class WalkingBird extends Bird +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "WalkingBird", + "description" => "A bird which nevers flies", + "key_type" => "", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "walkingbirds", + "db_key_field" => "walkingbirdid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_OverloadAttributeParams("species", array("allowed_values"=>array('geese', 'rooster', 'chicken', 'turckey'))); + MetaModel::Init_InheritFilters(); + } +} + +class FlyingBird extends Bird +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "FlyingBird", + "description" => "A bird which nevers flies", + "key_type" => "", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "flyingbirds", + "db_key_field" => "flyingbirdid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_OverloadAttributeParams("species", array("allowed_values"=>array('pie', 'corbeau'))); + MetaModel::Init_AddAttribute(new AttributeInteger("flyingspeed", array("label"=>"flying speed", "description"=>"flying at ms.s-1", "allowed_values"=>null, "sql"=>"headcount", "default_value"=>10, "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("flyingspeed"); + } +} + +class AnimalRelation extends dbObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "AnimalRelation", + "description" => "Link between two animals", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "a2a", + "db_key_field" => "linkid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + + // What makes it being a link... + MetaModel::Init_AddAttribute(new AttributeExternalKey("animal1", array("label"=>"source", "description"=>"the animal which does ...", "allowed_values"=>null, "sql"=>"a1", "targetclass"=>"Animal", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("animal2", array("label"=>"target", "description"=>"the animal to which something is done...", "allowed_values"=>null, "sql"=>"a2", "targetclass"=>"Animal", "is_null_allowed"=>false, "depends_on"=>array()))); + + //MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("animal1"); + MetaModel::Init_AddFilterFromAttribute("animal2"); + } +} + + +class EaterToEaten extends AnimalRelation +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "EaterToEaten", + "description" => "Animal 1 eats animal 2", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "eatertoeaten", + "db_key_field" => "eatertoeatonid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeEnum("DeadOrAlive", array("label"=>"DeadOrAlive", "description"=>"State in which it is ok for the eater to proceed", "allowed_values"=>new ValueSetEnum('dead, fresh, cooked'), "sql"=>"deadoralive", "default_value"=>"fresh", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("DeadOrAlive"); + } +} + +class Group extends dbObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "blah", + "name" => "Group", + "description" => "Group of animals", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "name", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "groups", + "db_key_field" => "groupid", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("name", array("label"=>"name", "description"=>"name", "allowed_values"=>null, "sql"=>"name", "default_value"=>"xxx", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalKey("leader", array("label"=>"leader", "description"=>"leader", "allowed_values"=>null, "sql"=>"leader", "targetclass"=>"Mammal", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("leader_name", array("label"=>"Leader Name", "description"=>"Name of the leader (defined on Mammal)", "allowed_values"=>null, "extkey_attcode"=> 'leader', "target_attcode"=>"name"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("leader_speed", array("label"=>"Leader Name", "description"=>"Speed of the leader (defined on Animal)", "allowed_values"=>null, "extkey_attcode"=> 'leader', "target_attcode"=>"speed"))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("name"); + MetaModel::Init_AddFilterFromAttribute("leader"); + MetaModel::Init_AddFilterFromAttribute("leader_name"); + MetaModel::Init_AddFilterFromAttribute("leader_speed"); + } +} + + +?> diff --git a/config-dist.php b/config-dist.php new file mode 100644 index 000000000..db5babff2 --- /dev/null +++ b/config-dist.php @@ -0,0 +1,38 @@ + 'localhost', + 'db_user' => 'itop', + 'db_pwd' => '1T0p', + 'db_name' => 'itopv06', + 'db_subname' => '', // use it to differentiate two applications instances running on the same DB +); + +// Modules: file names should be specified as a absolute paths + +$MyModules = array( + 'application' => array ( + '../application/menunode.class.inc.php', + '../application/audit.rule.class.inc.php', + // to be continued... + ), + 'business' => array ( + '../business/itop.business.class.inc.php' + // to be continued... + ), + 'addons' => array ( + 'user rights' => '../addons/userrights/userrightsmatrix.class.inc.php', + // other modules to come later + ) +); + + +?> diff --git a/config-test-farm.php b/config-test-farm.php new file mode 100644 index 000000000..3d1ab9381 --- /dev/null +++ b/config-test-farm.php @@ -0,0 +1,35 @@ + 'localhost', + 'db_user' => 'RomainDBLogin', + 'db_pwd' => '', + 'db_name' => 'TestFarm', + 'db_subname' => '', // use it to differentiate two applications instances running on the same DB +); + +// Modules: file names should be specified as a absolute paths + +$MyModules = array( + 'application' => array ( + // to be continued... + ), + 'business' => array ( + '../business/test_farm.class.inc.php', + // to be continued... + ), + 'addons' => array ( + //'user rights' => '/addons/userrights/userrightsnull.class.inc.php', // or userrightsmatrix.class.inc.php + // other modules to come later + ) +); + +?> diff --git a/config-test-mymodel.php b/config-test-mymodel.php new file mode 100644 index 000000000..e3176169d --- /dev/null +++ b/config-test-mymodel.php @@ -0,0 +1,36 @@ + 'localhost', + 'db_user' => 'itop', + 'db_pwd' => '1T0p', + 'db_name' => 'TestBizModelGenericItop', + 'db_subname' => 'tribute2itop', // use it to differentiate two applications instances running on the same DB +); + +// Modules: file names should be specified as a absolute paths + +$MyModules = array( + 'application' => array ( + // to be continued... + ), + 'business' => array ( + '../business/business_test.class.inc.php' + // to be continued... + ), + 'addons' => array ( + // other modules to come later + ) +); + + +?> diff --git a/core/MyHelpers.class.inc.php b/core/MyHelpers.class.inc.php new file mode 100644 index 000000000..532ca87c6 --- /dev/null +++ b/core/MyHelpers.class.inc.php @@ -0,0 +1,383 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +class MyHelpers +{ + public static function CheckValueInArray($sDescription, $value, $aData) + { + if (!in_array($value, $aData)) + { + self::HandleWrongValue($sDescription, $value, $aData); + } + } + + public static function CheckKeyInArray($sDescription, $key, $aData) + { + if (!array_key_exists($key, $aData)) + { + self::HandleWrongValue($sDescription, $key, array_keys($aData)); + } + } + + public static function HandleWrongValue($sDescription, $value, $aData) + { + if (count($aData) == 0) + { + $sArrayDesc = "{}"; + } + else + { + $sArrayDesc = "{".implode(", ", $aData)."}"; + } + // exit! + trigger_error("Wrong value for $sDescription, found '$value' while expecting a value in $sArrayDesc", E_USER_ERROR); + } + + // getmicrotime() + // format sss.mmmuuupppnnn + public static function getmicrotime() + { + list($usec, $sec) = explode(" ",microtime()); + return ((float)$usec + (float)$sec); + } + + /* + * MakeSQLComment + * converts hash into text comment which we can use in a (mySQL) query + */ + public static function MakeSQLComment ($aHash) + { + if (empty($aHash)) return ""; + $sComment = ""; + { + foreach($aHash as $sKey=>$sValue) + { + $sComment .= "\n-- ". $sKey ."=>" . $sValue; + } + } + return $sComment; + } + + public static function var_dump_html($aWords, $bFullDisplay = false) + { + echo "
\n";
+		if ($bFullDisplay)
+		{
+			print_r($aWords); // full dump!
+		}
+		else
+		{
+			var_dump($aWords); // truncate things when they are too big
+		}
+		echo "\n
\n"; + } + + public static function arg_dump_html() + { + echo "
\n";
+		echo "GET:\n";
+		var_dump($_GET);
+		echo "POST:\n";
+		var_dump($_POST);
+		echo "\n
\n"; + } + + public static function get_callstack_html($iLevelsToIgnore = 0, $aCallStack = null) + { + if ($aCallStack == null) $aCallStack = debug_backtrace(); + + $aCallStack = array_slice($aCallStack, $iLevelsToIgnore); + + $aDigestCallStack = array(); + $bFirstLine = true; + foreach ($aCallStack as $aCallInfo) + { + $sLine = empty($aCallInfo['line']) ? "" : $aCallInfo['line']; + $sFile = empty($aCallInfo['file']) ? "" : $aCallInfo['file']; + $sClass = empty($aCallInfo['class']) ? "" : $aCallInfo['class']; + $sType = empty($aCallInfo['type']) ? "" : $aCallInfo['type']; + $sFunction = empty($aCallInfo['function']) ? "" : $aCallInfo['function']; + + if ($bFirstLine) + { + $bFirstLine = false; + // For this line do not display the "function name" because + // that will be the name of our error handler for sure ! + $sFunctionInfo = "N/A"; + } + else + { + $args = ''; + if (empty($aCallInfo['args'])) $aCallInfo['args'] = array(); + foreach ($aCallInfo['args'] as $a) + { + if (!empty($args)) + { + $args .= ', '; + } + switch (gettype($a)) + { + case 'integer': + case 'double': + $args .= $a; + break; + case 'string': + $a = Str::pure2html(self::beautifulstr($a, 1024, true, true)); + $args .= "\"$a\""; + break; + case 'array': + $args .= 'Array('.count($a).')'; + break; + case 'object': + $args .= 'Object('.get_class($a).')'; + break; + case 'resource': + $args .= 'Resource('.strstr($a, '#').')'; + break; + case 'boolean': + $args .= $a ? 'True' : 'False'; + break; + case 'NULL': + $args .= 'Null'; + break; + default: + $args .= 'Unknown'; + } + } + $sFunctionInfo = "$sClass $sType $sFunction($args)"; + } + $aDigestCallStack[] = array('File'=>$sFile, 'Line'=>$sLine, 'Function'=>$sFunctionInfo); + } + return self::make_table_from_assoc_array($aDigestCallStack); + } + + public static function dump_callstack($iLevelsToIgnore = 0, $aCallStack = null) + { + return self::get_callstack_html($iLevelsToIgnore, $aCallStack); + } + + /////////////////////////////////////////////////////////////////////////////// + // Source: New + // Last modif: 2004/12/20 RQU + /////////////////////////////////////////////////////////////////////////////// + public static function make_table_from_assoc_array(&$aData) + { + if (!is_array($aData)) trigger_error("make_table_from_assoc_array: Error - the passed argument is not an array", E_USER_ERROR); + $aFirstRow = reset($aData); + if (!is_array($aFirstRow)) trigger_error("make_table_from_assoc_array: Error - the passed argument is not a bi-dimensional array", E_USER_ERROR); + $sOutput = ""; + $sOutput .= "\n"; + + // Table header + // + $sOutput .= " \n"; + foreach ($aFirstRow as $fieldname=>$trash) { + $sOutput .= " \n"; + } + $sOutput .= " \n"; + + // Table contents + // + $iCount = 0; + foreach ($aData as $aRow) { + $sStyle = ($iCount++ % 2 ? "STYLE=\"background-color : #eeeeee\"" : ""); + $sOutput .= " \n"; + foreach ($aRow as $data) { + if (strlen($data) == 0) { + $data = " "; + } + $sOutput .= " \n"; + } + $sOutput .= " \n"; + } + + $sOutput .= "
".$fieldname."
".$data."
\n"; + return $sOutput; + } + + public static function debug_breakpoint($arg) + { + echo "

Debug breakpoint

\n"; + MyHelpers::var_dump_html($arg); + MyHelpers::dump_callstack(); + exit; + } + public static function debug_breakpoint_notempty($arg) + { + if (empty($arg)) return; + echo "

Debug breakpoint (triggered on non-empty value)

\n"; + MyHelpers::var_dump_html($arg); + MyHelpers::dump_callstack(); + exit; + } + + /** + * utf8... converts non ASCII chars into '?' + * Decided after some complex investigations, to have the tools work fine (Oracle+Perl vs mySQL+PHP...) + */ + public static function utf8($strText) + { + return iconv("WINDOWS-1252", "ASCII//TRANSLIT", $strText); + } + + /** + * xmlentities() + * ... same as htmlentities, but designed for xml ! + */ + public static function xmlentities($string) + { + return str_replace( array( '&', '"', "'", '<', '>' ), array ( '&' , '"', ''' , '<' , '>' ), $string ); + } + + /** + * xmlencode() + * Encodes a string so that for sure it can be output as an xml data string + */ + public static function xmlencode($string) + { + return xmlentities(iconv("UTF-8", "UTF-8//IGNORE",$string)); + } + + /////////////////////////////////////////////////////////////////////////////// + // Source: New - format strings for output + // Last modif: 2005/01/18 RQU + /////////////////////////////////////////////////////////////////////////////// + public static function beautifulstr($sLongString, $iMaxLen, $bShowLen=false, $bShowTooltip=true) + { + if (!is_string($sLongString)) trigger_error("beautifulstr: expect a string as 1st argument", E_USER_ERROR); + + // Nothing to do if the string is short + if (strlen($sLongString) <= $iMaxLen) return $sLongString; + + // Truncate the string + $sSuffix = "..."; + if ($bShowLen) { + $sSuffix .= "(".strlen($sLongString)." chars)..."; + } + $sOutput = substr($sLongString, 0, $iMaxLen - strlen($sSuffix)).$sSuffix; + $sOutput = htmlspecialchars($sOutput); + + // Add tooltip if required + //if ($bShowTooltip) { + // $oTooltip = new gui_tooltip($sLongString); + // $sOutput = "get_mouseOver_code().">".$sOutput.""; + //} + return $sOutput; + } +} + +/** +Utility class: static methods for cleaning & escaping untrusted (i.e. +user-supplied) strings. +Any string can (usually) be thought of as being in one of these 'modes': +pure = what the user actually typed / what you want to see on the page / + what is actually stored in the DB +gpc = incoming GET, POST or COOKIE data +sql = escaped for passing safely to RDBMS via SQL (also, data from DB + queries and file reads if you have magic_quotes_runtime on--which + is rare) +html = safe for html display (htmlentities applied) +Always knowing what mode your string is in--using these methods to +convert between modes--will prevent SQL injection and cross-site scripting. +This class refers to its own namespace (so it can work in PHP 4--there is no +self keyword until PHP 5). Do not change the name of the class w/o changing +all the internal references. +Example usage: a POST value that you want to query with: +$username = Str::gpc2sql($_POST['username']); +*/ +//This sets SQL escaping to use slashes; for Sybase(/MSSQL)-style escaping +// ( ' --> '' ), set to true. +define('STR_SYBASE', false); +class Str +{ + public static function gpc2sql($gpc, $maxLength = false) + { + return self::pure2sql(self::gpc2pure($gpc), $maxLength); + } + public static function gpc2html($gpc, $maxLength = false) + { + return self::pure2html(self::gpc2pure($gpc), $maxLength); + } + public static function gpc2pure($gpc) + { + if (ini_get('magic_quotes_sybase')) $pure = str_replace("''", "'", $gpc); + else $pure = get_magic_quotes_gpc() ? stripslashes($gpc) : $gpc; + return $pure; + } + public static function html2pure($html) + { + return html_entity_decode($html); + } + public static function html2sql($html, $maxLength = false) + { + return self::pure2sql(self::html2pure($html), $maxLength); + } + public static function pure2html($pure, $maxLength = false) + { + return $maxLength + ? htmlentities(substr($pure, 0, $maxLength)) + : htmlentities($pure); + } + public static function pure2sql($pure, $maxLength = false) + { + if ($maxLength) $pure = substr($pure, 0, $maxLength); + return (STR_SYBASE) + ? str_replace("'", "''", $pure) + : addslashes($pure); + } + public static function sql2html($sql, $maxLength = false) + { + $pure = self::sql2pure($sql); + if ($maxLength) $pure = substr($pure, 0, $maxLength); + return self::pure2html($pure); + } + public static function sql2pure($sql) + { + return (STR_SYBASE) + ? str_replace("''", "'", $sql) + : stripslashes($sql); + } + + public static function xml2pure($xml) + { + // #@# - not implemented + return $xml; + } + public static function pure2xml($pure) + { + return self::xmlencode($pure); + } + + protected static function xmlentities($string) + { + return str_replace( array( '&', '"', "'", '<', '>' ), array ( '&' , '"', ''' , '<' , '>' ), $string ); + } + + /** + * xmlencode() + * Encodes a string so that for sure it can be output as an xml data string + */ + protected static function xmlencode($string) + { + return self::xmlentities(iconv("ISO-8859-1", "UTF-8//IGNORE",$string)); + } + + public static function islowcase($sString) + { + return (strtolower($sString) == $sString); + } +} + +?> diff --git a/core/archive.class.inc.php b/core/archive.class.inc.php new file mode 100644 index 000000000..6403fffca --- /dev/null +++ b/core/archive.class.inc.php @@ -0,0 +1,323 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +/** + * iTopArchive a class to manipulate (read/write) iTop archives with their catalog + * Each iTop archive is a zip file that contains (at the root of the archive) + * a file called catalog.xml holding the description of the archive + */ +class iTopArchive +{ + const read = 0; + const create = ZipArchive::CREATE; + + protected $m_sZipPath; + protected $m_oZip; + protected $m_sVersion; + protected $m_sTitle; + protected $m_sDescription; + protected $m_aPackages; + protected $m_aErrorMessages; + + /** + * Construct an iTopArchive object + * @param $sArchivePath string The full path the archive file + * @param $iMode integrer Either iTopArchive::read for reading an existing archive or iTopArchive::create for creating a new one. Updating is not supported (yet) + */ + public function __construct($sArchivePath, $iMode = iTopArchive::read) + { + $this->m_sZipPath = $sArchivePath; + $this->m_oZip = new ZipArchive(); + $this->m_oZip->open($this->m_sZipPath, $iMode); + $this->m_aErrorMessages = array(); + $this->m_sVersion = '1.0'; + $this->m_sTitle = ''; + $this->m_sDescription = ''; + $this->m_aPackages = array(); + } + + public function SetTitle($sTitle) + { + $this->m_sTitle = $sTitle; + } + + public function SetDescription($sDescription) + { + $this->m_sDescription = $sDescription; + } + + public function GetTitle() + { + return $this->m_sTitle; + } + + public function GetDescription() + { + return $this->m_sDescription; + } + + public function GetPackages() + { + return $this->m_aPackages; + } + + public function __destruct() + { + $this->m_oZip->close(); + } + + /** + * Get the error message explaining the latest error encountered + * @return array All the error messages encountered during the validation + */ + public function GetErrors() + { + return $this->m_aErrorMessages; + } + + /** + * Read the catalog from the archive (zip) file + * @param sPath string Path the the zip file + * @return boolean True in case of success, false otherwise + */ + public function ReadCatalog() + { + if ($this->IsValid()) + { + $sXmlCatalog = $this->m_oZip->getFromName('catalog.xml'); + $oParser = xml_parser_create(); + xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes); + xml_parser_free($oParser); + + $iIndex = $aIndexes['ARCHIVE'][0]; + $this->m_sVersion = $aValues[$iIndex]['attributes']['VERSION']; + $iIndex = $aIndexes['TITLE'][0]; + $this->m_sTitle = $aValues[$iIndex]['value']; + $iIndex = $aIndexes['DESCRIPTION'][0]; + if (array_key_exists('value', $aValues[$iIndex])) + { + // #@# implement a get_array_value(array, key, default) ? + $this->m_sDescription = $aValues[$iIndex]['value']; + } + + foreach($aIndexes['PACKAGE'] as $iIndex) + { + $this->m_aPackages[$aValues[$iIndex]['attributes']['HREF']] = array( 'type' => $aValues[$iIndex]['attributes']['TYPE'], 'title'=> $aValues[$iIndex]['attributes']['TITLE'], 'description' => $aValues[$iIndex]['value']); + } + + //echo "Archive path: {$this->m_sZipPath}
\n"; + //echo "Archive format version: {$this->m_sVersion}
\n"; + //echo "Title: {$this->m_sTitle}
\n"; + //echo "Description: {$this->m_sDescription}
\n"; + //foreach($this->m_aPackages as $aFile) + //{ + // echo "{$aFile['title']} ({$aFile['type']}): {$aFile['description']}
\n"; + //} + } + return true; + } + + public function WriteCatalog() + { + $sXml = "\n"; // split the XML closing tag that disturbs PSPad's syntax coloring + $sXml .= "\n"; + $sXml .= "{$this->m_sTitle}\n"; + $sXml .= "{$this->m_sDescription}\n"; + foreach($this->m_aPackages as $sFileName => $aFile) + { + $sXml .= "{$aFile['description']}\n"; + } + $sXml .= ""; + $this->m_oZip->addFromString('catalog.xml', $sXml); + } + + /** + * Add a package to the archive + * @param string $sExternalFilePath The path to the file to be added to the archive as a package (directories are not yet implemented) + * @param string $sFilePath The name of the file inside the archive + * @param string $sTitle A short title for this package + * @param string $sType Type of the package. SQL scripts must be of type 'text/sql' + * @param string $sDescription A longer description of the purpose of this package + * @return none + */ + public function AddPackage($sExternalFilePath, $sFilePath, $sTitle, $sType, $sDescription) + { + $this->m_aPackages[$sFilePath] = array('title' => $sTitle, 'type' => $sType, 'description' => $sDescription); + $this->m_oZip->addFile($sExternalFilePath, $sFilePath); + } + + /** + * Reads the contents of the given file from the archive + * @param string $sFileName The path to the file inside the archive + * @return string The content of the file read from the archive + */ + public function GetFileContents($sFileName) + { + return $this->m_oZip->getFromName($sFileName); + } + + /** + * Extracts the contents of the given file from the archive + * @param string $sFileName The path to the file inside the archive + * @param string $sDestinationFileName The path of the file to write + * @return none + */ + public function ExtractToFile($sFileName, $sDestinationFileName) + { + $iBufferSize = 64 * 1024; // Read 64K at a time + $oZipStream = $this->m_oZip->getStream($sFileName); + $oDestinationStream = fopen($sDestinationFileName, 'wb'); + while (!feof($oZipStream)) { + $sContents = fread($oZipStream, $iBufferSize); + fwrite($oDestinationStream, $sContents); + } + fclose($oZipStream); + fclose($oDestinationStream); + } + + /** + * Apply a SQL script taken from the archive. The package must be listed in the catalog and of type text/sql + * @param string $sFileName The path to the SQL package inside the archive + * @return boolean false in case of error, true otherwise + */ + public function ImportSql($sFileName, $sDatabase = 'itop') + { + if ( ($this->m_oZip->locateName($sFileName) == false) || (!isset($this->m_aPackages[$sFileName])) || ($this->m_aPackages[$sFileName]['type'] != 'text/sql')) + { + // invalid type or not listed in the catalog + return false; + } + $sTempName = tempnam("../tmp/", "sql"); + //echo "Extracting to: '$sTempName'
\n"; + $this->ExtractToFile($sFileName, $sTempName); + // Note: the command line below works on Windows with the right path to mysql !!! + $sCommandLine = 'type "'.$sTempName.'" | "/iTop/MySQL Server 5.0/bin/mysql.exe" -u root '.$sDatabase; + //echo "Executing: '$sCommandLine'
\n"; + exec($sCommandLine, $aOutput, $iRet); + //echo "Return code: $iRet
\n"; + //echo "Output:
\n";
+		//print_r($aOutput);
+		//echo "

\n"; + unlink($sTempName); + return ($iRet == 0); + } + + /** + * Dumps some part of the specified MySQL database into the archive as a text/sql package + * @param $sTitle string A short title for this SQL script + * @param $sDescription string A longer description of the purpose of this SQL script + * @param $sFileName string The name of the package inside the archive + * @param $sDatabase string name of the database + * @param $aTables array array or table names. If empty, all tables are dumped + * @param $bStructureOnly boolean Whether or not to dump the data or just the schema + * @return boolean False in case of error, true otherwise + */ + public function AddDatabaseDump($sTitle, $sDescription, $sFileName, $sDatabase = 'itop', $aTables = array(), $bStructureOnly = true) + { + $sTempName = tempnam("../tmp/", "sql"); + $sNoData = $bStructureOnly ? "--no-data" : ""; + $sCommandLine = "\"/iTop/MySQL Server 5.0/bin/mysqldump.exe\" --user=root --opt $sNoData --result-file=$sTempName $sDatabase ".implode(" ", $aTables); + //echo "Executing command: '$sCommandLine'
\n"; + exec($sCommandLine, $aOutput, $iRet); + //echo "Return code: $iRet
\n"; + //echo "Output:
\n";
+		//print_r($aOutput);
+		//echo "

\n"; + if ($iRet == 0) + { + $this->AddPackage($sTempName, $sFileName, $sTitle, 'text/sql', $sDescription); + } + //unlink($sTempName); + return ($iRet == 0); + } + + /** + * Check the consistency of the archive + * @return boolean True if the archive file is consistent + */ + public function IsValid() + { + // TO DO: use a DTD to validate the XML instead of this hand-made validation + $bResult = true; + $aMandatoryTags = array('ARCHIVE' => array('VERSION'), + 'TITLE' => array(), + 'DESCRIPTION' => array(), + 'PACKAGE' => array('TYPE', 'HREF', 'TITLE')); + + $sXmlCatalog = $this->m_oZip->getFromName('catalog.xml'); + $oParser = xml_parser_create(); + xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes); + xml_parser_free($oParser); + + foreach($aMandatoryTags as $sTag => $aAttributes) + { + // Check that all the required tags are present + if (!isset($aIndexes[$sTag])) + { + $this->m_aErrorMessages[] = "The XML catalog does not contain the mandatory tag $sTag."; + $bResult = false; + } + else + { + foreach($aIndexes[$sTag] as $iIndex) + { + switch($aValues[$iIndex]['type']) + { + case 'complete': + case 'open': + // Check that all the required attributes are present + foreach($aAttributes as $sAttribute) + { + if (!isset($aValues[$iIndex]['attributes'][$sAttribute])) + { + $this->m_aErrorMessages[] = "The tag $sTag ($iIndex) does not contain the required attribute $sAttribute."; + } + } + break; + + default: + // ignore other type of tags: close or cdata + } + } + } + } + return $bResult; + } +} +/* +// Unit test - reading an archive +$sArchivePath = '../tmp/archive.zip'; +$oArchive = new iTopArchive($sArchivePath, iTopArchive::read); +$oArchive->ReadCatalog(); +$oArchive->ImportSql('full_backup.sql'); + +// Writing an archive -- + +$sArchivePath = '../tmp/archive2.zip'; +$oArchive = new iTopArchive($sArchivePath, iTopArchive::create); +$oArchive->SetTitle('First Archive !'); +$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.'); +$oArchive->AddPackage('../tmp/schema.sql', 'test.sql', 'this is just a test', 'text/sql', 'My first attempt at creating an archive from PHP...'); +$oArchive->WriteCatalog(); + + +$sArchivePath = '../tmp/archive2.zip'; +$oArchive = new iTopArchive($sArchivePath, iTopArchive::create); +$oArchive->SetTitle('First Archive !'); +$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.'); +$oArchive->AddDatabaseDump('Test', 'This is my first automatic dump', 'schema.sql', 'itop', array('objects')); +$oArchive->WriteCatalog(); +*/ +?> diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php new file mode 100644 index 000000000..342e68ee3 --- /dev/null +++ b/core/attributedef.class.inc.php @@ -0,0 +1,989 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +abstract class AttributeDefinition +{ + abstract public function GetType(); + abstract public function GetTypeDesc(); + abstract public function GetEditClass(); + abstract public function GetDBFieldType(); + + protected $m_sCode; + private $m_aParams = array(); + private $m_sHostClass = array(); + protected function Get($sParamName) {return $this->m_aParams[$sParamName];} + + public function __construct($sCode, $aParams) + { + $this->m_sCode = $sCode; + $this->m_aParams = $aParams; + $this->ConsistencyCheck(); + } + public function OverloadParams($aParams) + { + foreach ($aParams as $sParam => $value) + { + if (!array_key_exists($sParam, $this->m_aParams)) + { + trigger_error("Unknown attribute definition parameter '$sParam', please select a value in {".implode(", ", $this->m_aParams)."}"); + } + else + { + $this->m_aParams[$sParam] = $value; + } + } + } + public function SetHostClass($sHostClass) + { + $this->m_sHostClass = $sHostClass; + } + public function GetHostClass() + { + return $this->m_sHostClass; + } + + // Note: I could factorize this code with the parameter management made for the AttributeDef class + // to be overloaded + static protected function ListExpectedParams() + { + return array("label", "description", "allowed_values"); + } + + private function ConsistencyCheck() + { + + // Check that any mandatory param has been specified + // + $aExpectedParams = $this->ListExpectedParams(); + foreach($aExpectedParams as $sParamName) + { + if (!array_key_exists($sParamName, $this->m_aParams)) + { + $aBacktrace = debug_backtrace(); + $sTargetClass = $aBacktrace[2]["class"]; + $sCodeInfo = $aBacktrace[1]["file"]." - ".$aBacktrace[1]["line"]; + trigger_error("ERROR missing parameter '$sParamName' in ".get_class($this)." declaration for class $sTargetClass ($sCodeInfo)
\n", E_USER_ERROR); + } + } + } + + // table, key field, name field + public function ListDBJoins() + { + return ""; + // e.g: return array("Site", "infrid", "name"); + } + public function IsDirectField() {return false;} + public function IsScalar() {return false;} + public function IsLinkSet() {return false;} + public function IsExternalKey($iType = EXTKEY_RELATIVE) {return false;} + public function IsExternalField() {return false;} + public function IsWritable() {return false;} + public function GetCode() {return $this->m_sCode;} + public function GetLabel() {return $this->Get("label");} + public function GetDescription() {return $this->Get("description");} + public function GetValuesDef() {return $this->Get("allowed_values");} + public function GetPrerequisiteAttributes() {return $this->Get("depends_on");} + //public function IsSearchableStd() {return $this->Get("search_std");} + //public function IsSearchableGlobal() {return $this->Get("search_global");} + //public function IsMandatory() {return $this->Get("is_mandatory");} + //public function GetMinVal() {return $this->Get("min");} + //public function GetMaxVal() {return $this->Get("max");} + //public function GetSize() {return $this->Get("size");} + //public function GetCheckRegExp() {return $this->Get("regexp");} + //public function GetCheckFunc() {return $this->Get("checkfunc");} + + // Definition: real value is what will be stored in memory and maintained by MetaModel + // DBObject::Set() relies on MakeRealValue() + // MetaModel::MakeQuery() relies on RealValueToSQLValue() + // DBObject::FromRow() relies on SQLToRealValue() + public function MakeRealValue($proposedValue) {return $proposedValue;} // force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!) + public function RealValueToSQLValue($value) {return $value;} // format value as a valuable SQL literal (quoted outside) + public function SQLValueToRealValue($value) {return $value;} // take the result of a fetch... and make it a PHP variable + + public function GetJSCheckFunc() + { + $sRegExp = $this->Get("regexp"); + if (empty($sRegExp)) return 'return true;'; + + return "return regexp('$sRegExp', myvalue);"; + } + public function CheckValue($value) + { + $sRegExp = $this->Get("regexp"); + if (empty($sRegExp)) return true; + + return preg_match(preg_escape($this->Get("regexp")), $value); + } + + public function MakeValue() + { + $sComputeFunc = $this->Get("compute_func"); + if (empty($sComputeFunc)) return null; + + return call_user_func($sComputeFunc); + } + + abstract public function DBGetUsedFields(); + abstract public function GetDefaultValue(); + + // + // To be overloaded in subclasses + // + + abstract public function GetBasicFilterOperators(); // returns an array of "opCode"=>"description" + abstract public function GetBasicFilterLooseOperator(); // returns an "opCode" + //abstract protected GetBasicFilterHTMLInput(); + abstract public function GetBasicFilterSQLExpr($sOpCode, $value); + + public function GetAsHTML($sValue) + { + return Str::pure2html($sValue); + } + + public function GetAsXML($sValue) + { + return Str::pure2xml($sValue); + } + + public function GetAsCSV($sValue, $sSeparator = ';', $sSepEscape = ',') + { + return str_replace($sSeparator, $sSepEscape, $sValue); + } +} + +/** + * Set of objects directly linked to an object, and being part of its definition + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeLinkedSet extends AttributeDefinition +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("depends_on", "linked_class", "ext_key_to_me", "count_min", "count_max")); + } + + public function GetType() {return "Array of objects";} + public function GetTypeDesc() {return "Any kind of objects [subclass] of the same class";} + public function GetEditClass() {return "List";} + public function GetDBFieldType() {return "N/A";} // should be moved out of the AttributeDef root class + + public function IsWritable() {return true;} + public function IsLinkSet() {return true;} + + public function GetDefaultValue() {return DBObjectSet::FromScratch($this->Get('linked_class'));} + + public function GetLinkedClass() {return $this->Get('linked_class');} + public function GetExtKeyToMe() {return $this->Get('ext_key_to_me');} + + public function DBGetUsedFields() {return array();} + public function GetBasicFilterOperators() {return array();} + public function GetBasicFilterLooseOperator() {return '';} + public function GetBasicFilterSQLExpr($sOpCode, $value) {return '';} + + public function GetAsHTML($sValue) + { + return "ERROR: LIST OF OBJECTS"; + } + + public function GetAsXML($sValue) + { + return "ERROR: LIST OF OBJECTS"; + } + + public function GetAsCSV($sValue, $sSeparator = ';', $sSepEscape = ',') + { + return "ERROR: LIST OF OBJECTS"; + } +} + +/** + * Set of objects linked to an object (n-n), and being part of its definition + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeLinkedSetIndirect extends AttributeLinkedSet +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("ext_key_to_remote")); + } + public function GetExtKeyToRemote() { return $this->Get('ext_key_to_remote'); } +} + +/** + * Abstract class implementing default filters for a DB column + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeDBFieldVoid extends AttributeDefinition +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("depends_on", "sql")); + } + + public function GetType() {return "Void";} + public function GetTypeDesc() {return "Any kind of value, from the DB";} + public function GetEditClass() {return "String";} + public function GetDBFieldType() {return "VARCHAR(255)";} + + public function IsDirectField() {return true;} + public function IsScalar() {return true;} + public function IsWritable() {return true;} + public function GetSQLExpr() {return $this->Get("sql");} + public function GetDefaultValue() {return "";} + public function IsNullAllowed() {return false;} + public function DBGetUsedFields() + { + // #@# bugge a mort... a suivre... + return array($this->Get("sql")); + } + + public function GetBasicFilterOperators() + { + return array("="=>"equals", "!="=>"differs from"); + } + public function GetBasicFilterLooseOperator() + { + return "="; + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + $sQValue = CMDBSource::Quote($value); + switch ($sOpCode) + { + case '!=': + return $this->GetSQLExpr()." != $sQValue"; + break; + case '=': + default: + return $this->GetSQLExpr()." = $sQValue"; + } + } +} + +/** + * Base class for all kind of DB attributes, with the exception of external keys + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeDBField extends AttributeDBFieldVoid +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("default_value", "is_null_allowed")); + } + public function GetDefaultValue() {return $this->Get("default_value");} + public function IsNullAllowed() {return strtolower($this->Get("is_null_allowed"));} +} + +/** + * Map an integer column to an attribute + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeInteger extends AttributeDBField +{ + static protected function ListExpectedParams() + { + return parent::ListExpectedParams(); + //return array_merge(parent::ListExpectedParams(), array()); + } + + public function GetType() {return "Integer";} + public function GetTypeDesc() {return "Numeric value (could be negative)";} + public function GetEditClass() {return "String";} + public function GetDBFieldType() {return "INT";} + + public function GetBasicFilterOperators() + { + return array( + "!="=>"differs from", + "="=>"equals", + ">"=>"greater (strict) than", + ">="=>"greater than", + "<"=>"less (strict) than", + "<="=>"less than", + "in"=>"in" + ); + } + public function GetBasicFilterLooseOperator() + { + // Unless we implement an "equals approximately..." or "same order of magnitude" + return "="; + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + $sQValue = CMDBSource::Quote($value); + switch ($sOpCode) + { + case '!=': + return $this->GetSQLExpr()." != $sQValue"; + break; + case '>': + return $this->GetSQLExpr()." > $sQValue"; + break; + case '>=': + return $this->GetSQLExpr()." >= $sQValue"; + break; + case '<': + return $this->GetSQLExpr()." < $sQValue"; + break; + case '<=': + return $this->GetSQLExpr()." <= $sQValue"; + break; + case 'in': + if (!is_array($value)) trigger_error("Expected an array for argument value (sOpCode='$sOpCode')"); + return $this->GetSQLExpr()." IN ('".implode("', '", $value)."')"; + break; + + case '=': + default: + return $this->GetSQLExpr()." = \"$value\""; + } + } + + public function MakeRealValue($proposedValue) + { + //return intval($proposedValue); could work as well + return (int)$proposedValue; + } + public function RealValueToSQLValue($value) + { + assert(is_numeric($value)); + return $value; // supposed to be an int + } + public function SQLValueToRealValue($value) + { + // Use cast (int) or intval() ? + return (int)$value; + + } +} + +/** + * Map a varchar column (size < ?) to an attribute + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeString extends AttributeDBField +{ + static protected function ListExpectedParams() + { + return parent::ListExpectedParams(); + //return array_merge(parent::ListExpectedParams(), array()); + } + + public function GetType() {return "String";} + public function GetTypeDesc() {return "Alphanumeric string";} + public function GetEditClass() {return "String";} + public function GetDBFieldType() {return "VARCHAR(255)";} + + public function GetBasicFilterOperators() + { + return array( + "="=>"equals", + "!="=>"differs from", + "Like"=>"equals (no case)", + "NotLike"=>"differs from (no case)", + "Contains"=>"contains", + "Begins with"=>"begins with", + "Finishes with"=>"finishes with" + ); + } + public function GetBasicFilterLooseOperator() + { + return "Contains"; + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + $sQValue = CMDBSource::Quote($value); + switch ($sOpCode) + { + case '=': + case '!=': + return $this->GetSQLExpr()." $sOpCode $sQValue"; + case 'Begins with': + return $this->GetSQLExpr()." LIKE ".CMDBSource::Quote("$value%"); + case 'Finishes with': + return $this->GetSQLExpr()." LIKE ".CMDBSource::Quote("%$value"); + case 'Contains': + return $this->GetSQLExpr()." LIKE ".CMDBSource::Quote("%$value%"); + case 'NotLike': + return $this->GetSQLExpr()." NOT LIKE $sQValue"; + case 'Like': + default: + return $this->GetSQLExpr()." LIKE $sQValue"; + } + } + + public function MakeRealValue($proposedValue) + { + return (string)$proposedValue; + // if (!settype($proposedValue, "string")) + // { + // trigger_error("Failed to change the type of '$proposedValue' to a string", E_USER_WARNING); + // } + } + public function RealValueToSQLValue($value) + { + assert(is_string($value)); + return $value; + } + public function SQLValueToRealValue($value) + { + return $value; + } +} + +/** + * Map a text column (size > ?) to an attribute + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeText extends AttributeString +{ + public function GetType() {return "Text";} + public function GetTypeDesc() {return "Multiline character string";} + public function GetEditClass() {return "Text";} + public function GetDBFieldType() {return "TEXT";} + + public function GetAsHTML($sValue) + { + return str_replace("\n", "
\n", parent::GetAsHTML($sValue)); + } + + public function GetAsXML($value) + { + return Str::pure2xml($value); + } + + public function GetAsCSV($value, $sSeparator = ';', $sSepEscape = ',') + { + return str_replace("\n", "[newline]", parent::GetAsCSV($sValue, $sSeparator, $sSepEscape)); + } +} + +/** + * Map a enum column to an attribute + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeEnum extends AttributeString +{ + static protected function ListExpectedParams() + { + return parent::ListExpectedParams(); + //return array_merge(parent::ListExpectedParams(), array()); + } + + public function GetType() {return "Enum";} + public function GetTypeDesc() {return "List of predefined alphanumeric strings";} + public function GetEditClass() {return "String";} + public function GetDBFieldType() + { + $oValDef = $this->GetValuesDef(); + if ($oValDef) + { + $aValues = CMDBSource::Quote($oValDef->GetValues(array(), ""), true); + } + else + { + $aValues = array(); + } + if (count($aValues) > 0) + { + return "ENUM(".implode(", ", $aValues).")"; + } + else + { + return "VARCHAR(255)"; // ENUM() is not an allowed syntax! + } + } + + public function GetBasicFilterOperators() + { + return parent::GetBasicFilterOperators(); + } + public function GetBasicFilterLooseOperator() + { + return parent::GetBasicFilterLooseOperator(); + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + return parent::GetBasicFilterSQLExpr($sOpCode, $value); + } +} + +/** + * Map a date+time column to an attribute + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeDate extends AttributeDBField +{ + const MYDATEFORMAT = "Y-m-d H:i:s"; + //const MYDATETIMEZONE = "UTC"; + const MYDATETIMEZONE = "Europe/Paris"; + static protected $const_TIMEZONE = null; // set once for all upon object construct + + static public function InitStatics() + { + // Init static constant once for all (remove when PHP allows real static const) + self::$const_TIMEZONE = new DateTimeZone(self::MYDATETIMEZONE); + + // #@# Init default timezone -> do not get a notice... to be improved !!! + date_default_timezone_set(self::MYDATETIMEZONE); + } + + static protected function ListExpectedParams() + { + return parent::ListExpectedParams(); + //return array_merge(parent::ListExpectedParams(), array()); + } + + public function GetType() {return "Date";} + public function GetTypeDesc() {return "Date and time";} + public function GetEditClass() {return "Date";} + public function GetDBFieldType() {return "TIMESTAMP";} + + public function GetBasicFilterOperators() + { + return array( + "="=>"equals", + "!="=>"differs from", + "<"=>"before", + "<="=>"before", + ">"=>"after (strictly)", + ">="=>"after", + "SameDay"=>"same day (strip time)", + "SameMonth"=>"same year/month", + "SameYear"=>"same year", + "Today"=>"today", + ">|"=>"after today + N days", + "<|"=>"before today + N days", + "=|"=>"equals today + N days", + ); + } + public function GetBasicFilterLooseOperator() + { + // Unless we implement a "same xxx, depending on given precision" ! + return "="; + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + $sQValue = CMDBSource::Quote($value); + + switch ($sOpCode) + { + case '=': + case '!=': + case '<': + case '<=': + case '>': + case '>=': + return $this->GetSQLExpr()." $sOpCode $sQValue"; + case 'SameDay': + return "DATE(".$this->GetSQLExpr().") = DATE($sQValue)"; + case 'SameMonth': + return "DATE_FORMAT(".$this->GetSQLExpr().", '%Y-%m') = DATE_FORMAT($sQValue, '%Y-%m')"; + case 'SameYear': + return "MONTH(".$this->GetSQLExpr().") = MONTH($sQValue)"; + case 'Today': + return "DATE(".$this->GetSQLExpr().") = CURRENT_DATE()"; + case '>|': + return "DATE(".$this->GetSQLExpr().") > DATE_ADD(CURRENT_DATE(), INTERVAL $sQValue DAY)"; + case '<|': + return "DATE(".$this->GetSQLExpr().") < DATE_ADD(CURRENT_DATE(), INTERVAL $sQValue DAY)"; + case '=|': + return "DATE(".$this->GetSQLExpr().") = DATE_ADD(CURRENT_DATE(), INTERVAL $sQValue DAY)"; + default: + return $this->GetSQLExpr()." = $sQValue"; + } + } + + public function MakeRealValue($proposedValue) + { + if (!is_numeric($proposedValue)) + { + return $proposedValue; + } + else + { + return date("Y-m-d H:i:s", $proposedValue); + } + trigger_error("Invalid type for a date (found ".gettype($proposedValue)." and accepting string/int/DateTime)", E_USER_ERROR); + return null; + } + public function RealValueToSQLValue($value) + { + if (empty($value)) + { + // Make a valid date for MySQL. TO DO: support NULL as a literal value for fields that can be null. + return '0000-00-00 00:00:00'; + } + return $value; + } + public function SQLValueToRealValue($value) + { + return $value; + } + + public function GetAsHTML($value) + { + return Str::pure2html($value); + } + + public function GetAsXML($value) + { + return Str::pure2xml($value); + } + + public function GetAsCSV($value, $sSeparator = ';', $sSepEscape = ',') + { + return str_replace($sSeparator, $sSepEscape, $value); + } +} + +// Init static constant once for all (remove when PHP allows real static const) +AttributeDate::InitStatics(); + + +/** + * Map a foreign key to an attribute + * AttributeExternalKey and AttributeExternalField may be an external key + * the difference is that AttributeExternalKey corresponds to a column into the defined table + * where an AttributeExternalField corresponds to a column into another table (class) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeExternalKey extends AttributeDBFieldVoid +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("targetclass", "is_null_allowed")); + } + + public function GetType() {return "Extkey";} + public function GetTypeDesc() {return "Link to another object";} + public function GetEditClass() {return "ExtKey";} + public function GetDBFieldType() {return "INT";} + + public function IsExternalKey($iType = EXTKEY_RELATIVE) {return true;} + public function GetTargetClass($iType = EXTKEY_RELATIVE) {return $this->Get("targetclass");} + public function GetKeyAttDef($iType = EXTKEY_RELATIVE){return $this;} + public function GetKeyAttCode() {return $this->GetCode();} + + + public function GetDefaultValue() {return 0;} + public function IsNullAllowed() {return $this->Get("is_null_allowed");} + + public function GetBasicFilterOperators() + { + return parent::GetBasicFilterOperators(); + } + public function GetBasicFilterLooseOperator() + { + return parent::GetBasicFilterLooseOperator(); + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + return parent::GetBasicFilterSQLExpr($sOpCode, $value); + } + + // overloaded here so that an ext key always have the answer to + // "what are you possible values?" + public function GetValuesDef() + { + $oValSetDef = $this->Get("allowed_values"); + if (!$oValSetDef) + { + // Let's propose every existing value + $oValSetDef = new ValueSetObjects($this->GetTargetClass()); + } + return $oValSetDef; + } +} + +/** + * An attribute which corresponds to an external key (direct or indirect) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeExternalField extends AttributeDefinition +{ + + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("extkey_attcode", "target_attcode")); + } + + public function GetType() {return "ExtkeyField";} + public function GetTypeDesc() {return "Field of an object pointed to by the current object";} + public function GetEditClass() {return "ExtField";} + public function GetDBFieldType() + { + trigger_error("external attribute: does it make any sense to request its type ?", E_USER_WARNING); + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetDBFieldType(); + } + + public function IsExternalKey($iType = EXTKEY_RELATIVE) + { + switch($iType) + { + case EXTKEY_ABSOLUTE: + // see further + $oRemoteAtt = $this->GetExtAttDef(); + return $oRemoteAtt->IsExternalKey($iType); + + case EXTKEY_RELATIVE: + return false; + + default: + trigger_error("Unexpected value for argument iType: '$iType'", E_USER_ERROR); + } + } + + public function GetTargetClass($iType = EXTKEY_RELATIVE) + { + return $this->GetKeyAttDef($iType)->GetTargetClass(); + } + + public function IsExternalField() {return true;} + public function GetKeyAttCode() {return $this->Get("extkey_attcode");} + public function GetExtAttCode() {return $this->Get("target_attcode");} + + public function GetKeyAttDef($iType = EXTKEY_RELATIVE) + { + switch($iType) + { + case EXTKEY_ABSOLUTE: + // see further + $oRemoteAtt = $this->GetExtAttDef(); + if ($oRemoteAtt->IsExternalField()) + { + return $oRemoteAtt->GetKeyAttDef(EXTKEY_ABSOLUTE); + } + else if ($oRemoteAtt->IsExternalKey()) + { + return $oRemoteAtt; + } + return $this->GetKeyAttDef(EXTKEY_RELATIVE); // which corresponds to the code hereafter ! + + case EXTKEY_RELATIVE: + return MetaModel::GetAttributeDef($this->GetHostClass(), $this->Get("extkey_attcode")); + + default: + trigger_error("Unexpected value for argument iType: '$iType'", E_USER_ERROR); + } + } + + public function GetExtAttDef() + { + $oKeyAttDef = $this->GetKeyAttDef(); + $oExtAttDef = MetaModel::GetAttributeDef($oKeyAttDef->Get("targetclass"), $this->Get("target_attcode")); + return $oExtAttDef; + } + + public function GetSQLExpr() + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetSQLExpr(); + } + public function DBGetUsedFields() + { + // No field is used but the one defined in the field of the external class + // #@# so what ? + return array(); + } + + public function GetDefaultValue() + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetDefaultValue(); + } + public function IsNullAllowed() + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->IsNullAllowed(); + } + + public function GetBasicFilterOperators() + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetBasicFilterOperators(); + } + public function GetBasicFilterLooseOperator() + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetBasicFilterLooseOperator(); + } + + public function GetBasicFilterSQLExpr($sOpCode, $value) + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetBasicFilterSQLExpr($sOpCode, $value); + } + + public function MakeRealValue($proposedValue) + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->MakeRealValue($proposedValue); + } + public function RealValueToSQLValue($value) + { + // This one could be used in case of filtering only + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->RealValueToSQLValue($value); + } + public function SQLValueToRealValue($value) + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->SQLValueToRealValue($value); + } + public function GetAsHTML($value) + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetAsHTML($value); + } + public function GetAsXML($value) + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetAsXML($value); + } + public function GetAsCSV($value, $sSeparator = ';', $sSepEscape = ',') + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetAsCSV($value); + } +} + +/** + * Map a varchar column to an URL (formats the ouput in HMTL) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class AttributeURL extends AttributeString +{ + static protected function ListExpectedParams() + { + //return parent::ListExpectedParams(); + return array_merge(parent::ListExpectedParams(), array("target", "label")); + } + + public function GetType() {return "Url";} + public function GetTypeDesc() {return "Absolute or relative URL as a text string";} + public function GetEditClass() {return "String";} + + public function GetAsHTML($sValue) + { + $sTarget = $this->Get("target"); + if (empty($sTarget)) $sTarget = "_blank"; + $sLabel = Str::pure2html($sValue); + if (strlen($sLabel) > 40) + { + // Truncate the length to about 40 characters, by removing the middle + $sLabel = substr($sLabel, 0, 25).'...'.substr($sLabel, -15); + } + return "$sLabel"; + } +} + +?> diff --git a/core/cmdbchange.class.inc.php b/core/cmdbchange.class.inc.php new file mode 100644 index 000000000..02d011a04 --- /dev/null +++ b/core/cmdbchange.class.inc.php @@ -0,0 +1,44 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class CMDBChange extends DBObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "core/cmdb", + "name" => "change", + "description" => "Changes tracking", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "date", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "priv_change", + "db_key_field" => "id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeDate("date", array("label"=>"date", "description"=>"date and time at which the changes have been recorded", "allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("label"=>"misc. info", "description"=>"caller's defined information", "allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); + + //MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("date"); + MetaModel::Init_AddFilterFromAttribute("userinfo"); + } + +} + +?> diff --git a/core/cmdbchangeop.class.inc.php b/core/cmdbchangeop.class.inc.php new file mode 100644 index 000000000..9c019d0c4 --- /dev/null +++ b/core/cmdbchangeop.class.inc.php @@ -0,0 +1,165 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +class CMDBChangeOp extends DBObject +{ + public static function Init() + { + $aParams = array + ( + "category" => "core/cmdb", + "name" => "change operation", + "description" => "Change operations tracking", + "key_type" => "autoincrement", + "key_label" => "", + "name_attcode" => "change", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "priv_changeop", + "db_key_field" => "id", + "db_finalclass_field" => "optype", + ); + MetaModel::Init_Params($aParams); + //MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeExternalKey("change", array("label"=>"change", "description"=>"change", "allowed_values"=>null, "sql"=>"changeid", "targetclass"=>"CMDBChange", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeExternalField("date", array("label"=>"date", "description"=>"date and time of the change", "allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"date"))); + MetaModel::Init_AddAttribute(new AttributeExternalField("userinfo", array("label"=>"user", "description"=>"who made this change", "allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"userinfo"))); + MetaModel::Init_AddAttribute(new AttributeString("objclass", array("label"=>"object class", "description"=>"object class", "allowed_values"=>null, "sql"=>"objclass", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("objkey", array("label"=>"object id", "description"=>"object id", "allowed_values"=>null, "sql"=>"objkey", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + + MetaModel::Init_AddFilterFromAttribute("objclass"); + MetaModel::Init_AddFilterFromAttribute("objkey"); + MetaModel::Init_AddFilterFromAttribute("date"); + MetaModel::Init_AddFilterFromAttribute("userinfo"); + } +} + + + +/** + * Record the creation of an object + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class CMDBChangeOpCreate extends CMDBChangeOp +{ + public static function Init() + { + $aParams = array + ( + "category" => "core/cmdb", + "name" => "object creation", + "description" => "Object creation tracking", + "key_type" => "", + "key_label" => "", + "name_attcode" => "change", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "priv_changeop_create", + "db_key_field" => "id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + + MetaModel::Init_InheritFilters(); + } +} + + +/** + * Record the deletion of an object + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class CMDBChangeOpDelete extends CMDBChangeOp +{ + public static function Init() + { + $aParams = array + ( + "category" => "core/cmdb", + "name" => "object deletion", + "description" => "Object deletion tracking", + "key_type" => "", + "key_label" => "", + "name_attcode" => "change", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "priv_changeop_delete", + "db_key_field" => "id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + + MetaModel::Init_InheritFilters(); + } +} + + +/** + * Record the modification of an attribute + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class CMDBChangeOpSetAttribute extends CMDBChangeOp +{ + public static function Init() + { + $aParams = array + ( + "category" => "core/cmdb", + "name" => "object change", + "description" => "Object properties change tracking", + "key_type" => "", + "key_label" => "", + "name_attcode" => "change", + "state_attcode" => "", + "reconc_keys" => array(), + "db_table" => "priv_changeop_setatt", + "db_key_field" => "id", + "db_finalclass_field" => "", + ); + MetaModel::Init_Params($aParams); + MetaModel::Init_InheritAttributes(); + MetaModel::Init_AddAttribute(new AttributeString("attcode", array("label"=>"Attribute", "description"=>"code of the modified property", "allowed_values"=>null, "sql"=>"attcode", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("newvalue", array("label"=>"New value", "description"=>"new value of the attribute", "allowed_values"=>null, "sql"=>"newvalue", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); + + MetaModel::Init_InheritFilters(); + MetaModel::Init_AddFilterFromAttribute("attcode"); + MetaModel::Init_AddFilterFromAttribute("newvalue"); + + // Display lists + MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'newvalue')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'newvalue')); // Attributes to be displayed for a list + } +} + +?> diff --git a/core/cmdbobject.class.inc.php b/core/cmdbobject.class.inc.php new file mode 100644 index 000000000..7a98f58f9 --- /dev/null +++ b/core/cmdbobject.class.inc.php @@ -0,0 +1,424 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +require_once('coreexception.class.inc.php'); + +require_once('config.class.inc.php'); + +require_once('attributedef.class.inc.php'); +require_once('filterdef.class.inc.php'); +require_once('stimulus.class.inc.php'); +require_once('valuesetdef.class.inc.php'); +require_once('MyHelpers.class.inc.php'); + +require_once('expression.class.inc.php'); + +require_once('cmdbsource.class.inc.php'); +require_once('sqlquery.class.inc.php'); +require_once('oql/oqlquery.class.inc.php'); +require_once('oql/oqlexception.class.inc.php'); +require_once('oql/oql-parser.php'); +require_once('oql/oql-lexer.php'); +require_once('oql/oqlinterpreter.class.inc.php'); + +require_once('dbobject.class.php'); +require_once('dbobjectsearch.class.php'); +require_once('dbobjectset.class.php'); + +require_once('cmdbchange.class.inc.php'); +require_once('cmdbchangeop.class.inc.php'); + +require_once('userrights.class.inc.php'); + +// +// Error handling +// To be finalized... or removed ? +// +function cmdbErrorHandler($errno, $errstr, $errfile, $errline) +{ +// font-family: Courier-New, Courier, Arial, Helevtica; + $sErrorStyle = " + background-color: #ffaaaa; + color: #000000; + border: 1px dashed #000000; + padding: 0.25em; + margin-top: 1em; + "; + $sCallStackStyle = " + font-size: smaller; + background-color: #ffcccc; + color: #000000; + border: 1px dashed #000000; + padding: 0.25em; + margin-top: 1em; + "; + + switch ($errno) + { + case E_USER_ERROR: + case E_ERROR: + echo "
\n"; + echo "Error [$errno] $errstr
\n"; + echo "
\n"; + MyHelpers::dump_callstack(1); + echo "
\n"; + echo "Hereafter the biz model internals:
\n"; + echo "
\n";
+		MetaModel::static_var_dump();
+		echo "
\n"; + echo "Aborting...
\n"; + echo "
\n"; + exit(1); + break; + case E_USER_WARNING: + case E_WARNING: + echo "
\n"; + echo "Warning [$errno] $errstr
\n"; + echo "
\n"; + MyHelpers::dump_callstack(1); + echo "
\n"; + echo "
\n"; + break; + case E_USER_NOTICE: + case E_NOTICE: + echo "
\n"; + echo "Notice [$errno] $errstr
\n"; + echo "
\n"; + MyHelpers::dump_callstack(1); + echo "
\n"; + echo "
\n"; + break; + default: + echo "Unknown error type: [$errno] $errstr
\n"; + MyHelpers::dump_callstack(1); + break; + } +} + +error_reporting(E_ALL | E_STRICT); +//set_error_handler("cmdbErrorHandler"); + + + +// +// +// + + +/** + * A persistent object, which changes are accurately recorded + * + * @package iTopORM + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +abstract class CMDBObject extends DBObject +{ + protected $m_datCreated; + protected $m_datUpdated; + protected static $m_oCurrChange = null; + + + private function RecordObjCreation(CMDBChange $oChange) + { + $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate"); + $oMyChangeOp->Set("change", $oChange->GetKey()); + $oMyChangeOp->Set("objclass", get_class($this)); + $oMyChangeOp->Set("objkey", $this->GetKey()); + $iId = $oMyChangeOp->DBInsert(); + } + private function RecordObjDeletion(CMDBChange $oChange, $objkey) + { + $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpDelete"); + $oMyChangeOp->Set("change", $oChange->GetKey()); + $oMyChangeOp->Set("objclass", get_class($this)); + $oMyChangeOp->Set("objkey", $objkey); + $iId = $oMyChangeOp->DBInsert(); + } + private function RecordAttChanges(CMDBChange $oChange, array $aValues = array()) + { + // $aValues is an array of $sAttCode => $value + // ... some values... + // + if (empty($aValues)) + { + // ... or every object values + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsLinkSet()) continue; // #@# temporary + $aValues[$sAttCode] = $this->Get($sAttCode); + } + } + foreach ($aValues as $sAttCode=> $value) + { + $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + if ($oAttDef->IsLinkSet()) continue; // #@# temporary + $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttribute"); + $oMyChangeOp->Set("change", $oChange->GetKey()); + $oMyChangeOp->Set("objclass", get_class($this)); + $oMyChangeOp->Set("objkey", $this->GetKey()); + $oMyChangeOp->Set("attcode", $sAttCode); + $oMyChangeOp->Set("newvalue", $value); + $iId = $oMyChangeOp->DBInsert(); + } + } + + public function DBInsert() + { + if(!is_object(self::$m_oCurrChange)) + { + trigger_error("DBInsert() could not be used here, please use DBInsertTracked() instead", E_USER_ERROR); + } + return $this->DBInsertTracked_Internal(); + } + + public function DBInsertTracked(CMDBChange $oChange) + { + self::$m_oCurrChange = $oChange; + $this->DBInsertTracked_Internal(); + self::$m_oCurrChange = null; + } + + protected function DBInsertTracked_Internal() + { + $ret = parent::DBInsert(); + $this->RecordObjCreation(self::$m_oCurrChange); + $this->RecordAttChanges(self::$m_oCurrChange); + return $ret; + } + + public function DBClone($newKey = null) + { + if(!self::$m_oCurrChange) + { + trigger_error("DBClone() could not be used here, please use DBCloneTracked() instead", E_USER_ERROR); + } + return $this->DBCloneTracked_Internal(); + } + + public function DBCloneTracked(CMDBChange $oChange, $newKey = null) + { + self::$m_oCurrChange = $oChange; + $this->DBCloneTracked_Internal($newKey); + self::$m_oCurrChange = null; + } + + protected function DBCloneTracked_Internal($newKey = null) + { + $newKey = parent::DBClone($newKey); + $oClone = MetaModel::GetObject(get_class($this), $newKey); + + $oClone->RecordObjCreation(self::$m_oCurrChange); + $oClone->RecordAttChanges(self::$m_oCurrChange); + return $newKey; + } + + public function DBUpdate() + { + if(!self::$m_oCurrChange) + { + trigger_error("DBUpdate() could not be used here, please use DBUpdateTracked() instead", E_USER_ERROR); + } + return $this->DBUpdateTracked_internal(); + } + + public function DBUpdateTracked(CMDBChange $oChange) + { + self::$m_oCurrChange = $oChange; + $this->DBUpdateTracked_Internal(); + self::$m_oCurrChange = null; + } + + protected function DBUpdateTracked_Internal() + { + // Copy the changes list before the update (the list should be reset afterwards) + $aChanges = $this->ListChanges(); + if (count($aChanges) == 0) + { + trigger_error("Attempting to update an unchanged object", E_USER_NOTICE); + return; + } + + $ret = parent::DBUpdate(); + $this->RecordAttChanges(self::$m_oCurrChange, $aChanges); + return $ret; + } + + public function DBDelete() + { + if(!self::$m_oCurrChange) + { + trigger_error("DBDelete() could not be used here, please use DBDeleteTracked() instead", E_USER_ERROR); + } + return $this->DBDeleteTracked_Internal(); + } + + public function DBDeleteTracked(CMDBChange $oChange) + { + self::$m_oCurrChange = $oChange; + $this->DBDeleteTracked_Internal(); + self::$m_oCurrChange = null; + } + + protected function DBDeleteTracked_Internal() + { + $prevkey = $this->GetKey(); + $ret = parent::DBDelete(); + $this->RecordObjDeletion(self::$m_oCurrChange, $prevkey); + return $ret; + } + + public static function BulkDelete(DBObjectSearch $oFilter) + { + if(!self::$m_oCurrChange) + { + trigger_error("BulkDelete() could not be used here, please use BulkDeleteTracked() instead", E_USER_ERROR); + } + return $this->BulkDeleteTracked_Internal($oFilter); + } + + public static function BulkDeleteTracked(CMDBChange $oChange, DBObjectSearch $oFilter) + { + self::$m_oCurrChange = $oChange; + $this->BulkDeleteTracked_Internal($oFilter); + self::$m_oCurrChange = null; + } + + protected static function BulkDeleteTracked_Internal(DBObjectSearch $oFilter) + { + trigger_error("Change tracking not tested for bulk operations", E_USER_WARNING); + + // Get the list of objects to delete (and record data before deleting the DB records) + $oObjSet = new CMDBObjectSet($oFilter); + $aObjAndKeys = array(); // array of pkey=>object + while ($oItem = $oObjSet->Fetch()) + { + $aObjAndKeys[$oItem->GetKey()] = $oItem; + } + $oObjSet->FreeResult(); + + // Delete in one single efficient query + $ret = parent::BulkDelete($oFilter); + // Record... in many queries !!! + foreach($aObjAndKeys as $prevkey=>$oItem) + { + $oItem->RecordObjDeletion(self::$m_oCurrChange, $prevkey); + } + return $ret; + } + + public static function BulkUpdate(DBObjectSearch $oFilter, array $aValues) + { + if(!self::$m_oCurrChange) + { + trigger_error("BulkUpdate() could not be used here, please use BulkUpdateTracked() instead", E_USER_ERROR); + } + return $this->BulkUpdateTracked_Internal($oFilter, $aValues); + } + + public static function BulkUpdateTracked(CMDBChange $oChange, DBObjectSearch $oFilter, array $aValues) + { + self::$m_oCurrChange = $oChange; + $this->BulkUpdateTracked_Internal($oFilter, $aValues); + self::$m_oCurrChange = null; + } + + protected static function BulkUpdateTracked_Internal(DBObjectSearch $oFilter, array $aValues) + { + // $aValues is an array of $sAttCode => $value + + // Get the list of objects to update (and load it before doing the change) + $oObjSet = new CMDBObjectSet($oFilter); + $oObjSet->Load(); + + // Update in one single efficient query + $ret = parent::BulkUpdate($oFilter, $aValues); + + // Record... in many queries !!! + while ($oItem = $oObjSet->Fetch()) + { + $aChangedValues = $oItem->ListChangedValues($aValues); + $oItem->RecordAttChanges(self::$m_oCurrChange, $aChangedValues); + } + return $ret; + } +} + + + +/** + * TODO: investigate how to get rid of this class that was made to workaround some language limitation... or a poor design! + * + * @package iTopORM + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class CMDBObjectSet extends DBObjectSet +{ + // this is the public interface (?) + + // I have to define those constructors here... :-( + // just to get the right object class in return. + // I have to think again to those things: maybe it will work fine if a have a constructor define here (?) + + static public function FromScratch($sClass) + { + $oFilter = new CMDBSearchFilter($sClass); + $oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE + // NOTE: THIS DOES NOT WORK IF m_bLoaded is private... + // BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!! + $oRetSet->m_bLoaded = true; // no DB load + return $oRetSet; + } + + static public function FromArray($sClass, $aObjects) + { + $oFilter = new CMDBSearchFilter($sClass); + $oRetSet = new CMDBObjectSet($oFilter); // THE ONLY DIFF IS HERE + // NOTE: THIS DOES NOT WORK IF m_bLoaded is private... + // BUT IT THAT CASE YOU DO NOT GET ANY ERROR !!!!! + $oRetSet->m_bLoaded = true; // no DB load + $oRetSet->AddObjectArray($aObjects); + return $oRetSet; + } + +} + +/** + * TODO: investigate how to get rid of this class that was made to workaround some language limitation... or a poor design! + * + * @package iTopORM + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class CMDBSearchFilter extends DBObjectSearch +{ + // this is the public interface (?) +} + + +?> diff --git a/core/cmdbsource.class.inc.php b/core/cmdbsource.class.inc.php new file mode 100644 index 000000000..b0a332f1b --- /dev/null +++ b/core/cmdbsource.class.inc.php @@ -0,0 +1,386 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +require_once('MyHelpers.class.inc.php'); + +class MySQLException extends CoreException +{ + public function __construct($sIssue, $aContext) + { + $aContext['mysql_error'] = mysql_error(); + parent::__construct($sIssue, $aContext); + } +} + + +class CMDBSource +{ + protected static $m_sDBHost; + protected static $m_sDBUser; + protected static $m_sDBPwd; + protected static $m_sDBName; + protected static $m_resDBLink; + + public static function Init($sServer, $sUser, $sPwd, $sSource = '') + { + self::$m_sDBHost = $sServer; + self::$m_sDBUser = $sUser; + self::$m_sDBPwd = $sPwd; + self::$m_sDBName = $sSource; + if (!self::$m_resDBLink = mysql_pconnect($sServer, $sUser, $sPwd)) + { + throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser)); + } + if (!empty($sSource)) + { + if (!mysql_select_db($sSource, self::$m_resDBLink)) + { + throw new MySQLException('Could not select DB', array('db_name'=>$sSource)); + } + } + } + + public static function IsDB($sSource) + { + $aDBs = self::QueryToCol('SHOW DATABASES', 'Database'); + + // Show Database does return the DB names in lower case + $sSourceRef = strtolower($sSource); + return (in_array($sSourceRef, $aDBs)); + } + + public static function SelectDB($sSource) + { + if (!mysql_select_db($sSource, self::$m_resDBLink)) + { + throw new MySQLException('Could not select DB', array('db_name'=>$sSource)); + } + self::$m_sDBName = $sSource; + } + + public static function CreateDB($sSource) + { + self::Query("CREATE DATABASE `$sSource`"); + self::SelectDB($sSource); + } + + public static function DropDB($sDBToDrop = '') + { + if (empty($sDBToDrop)) + { + $sDBToDrop = self::$m_sDBName; + } + self::Query("DROP DATABASE `$sDBToDrop`"); + if ($sDBToDrop == self::$m_sDBName) + { + self::$m_sDBName = ''; + } + } + + public static function CreateTable($sQuery) + { + $res = self::Query($sQuery); + self::_TablesInfoCacheReset(); // reset the table info cache! + return $res; + } + + public static function DropTable($sTable) + { + $res = self::Query("DROP TABLE `$sTable`"); + self::_TablesInfoCacheReset(true); // reset the table info cache! + return $res; + } + + public static function DBHost() {return self::$m_sDBHost;} + public static function DBUser() {return self::$m_sDBUser;} + public static function DBPwd() {return self::$m_sDBPwd;} + public static function DBName() {return self::$m_sDBName;} + + public static function Quote($value, $bAlways = false, $cQuoteStyle = "'") + { + // Quote variable and protect against SQL injection attacks + // Code found in the PHP documentation: quote_smart($value) + + // bAlways should be set to true when the purpose is to create a IN clause, + // otherwise and if there is a mix of strings and numbers, the clause + // would always be false + + if (is_array($value)) + { + $aRes = array(); + foreach ($value as $key => $itemvalue) + { + $aRes[$key] = self::Quote($itemvalue, $bAlways, $cQuoteStyle); + } + return $aRes; + } + + // Stripslashes + if (get_magic_quotes_gpc()) + { + $value = stripslashes($value); + } + // Quote if not a number or a numeric string + if ($bAlways || !is_numeric($value)) + { + $value = $cQuoteStyle . mysql_real_escape_string($value, self::$m_resDBLink) . $cQuoteStyle; + } + return $value; + } + + public static function Query($sSQLQuery) + { + // Add info into the query as a comment, for easier error tracking + // + //if ($user_contact) $aTraceInf['userID'] = $user_contact->get_key(); + //$aTraceInf['file'] = __FILE__; + if ($_SERVER['REQUEST_URI']) $aTraceInf['requestURI'] = $_SERVER['REQUEST_URI']; + $i = 0; + foreach(debug_backtrace() as $aCallData) + { + $sClass = key_exists("class", $aCallData) ? $aCallData["class"]."::" : ""; + //if ($aCallData['function'] !== 'mysql_simple_query' AND $sClass !== 'r2_set::') + //{ + if ($i == 3) break; + $aTraceInf['function'.$i] = $sClass.$aCallData["function"]." on line ".$aCallData['line']; + $i++; + //} + } + // disabled until we need it really! + // $sSQLQuery = $sSQLQuery.MyHelpers::MakeSQLComment($aTraceInf); + + $mu_t1 = MyHelpers::getmicrotime(); + $result = mysql_query($sSQLQuery, self::$m_resDBLink); + if (!$result) + { + throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery)); + } + $mu_t2 = MyHelpers::getmicrotime(); + // #@# todo - query_trace($sSQLQuery, $mu_t2 - $mu_t1); + + return $result; + } + + public static function GetInsertId() + { + return mysql_insert_id(self::$m_resDBLink); + } + public static function InsertInto($sSQLQuery) + { + if (self::Query($sSQLQuery)) + { + return self::GetInsertId(); + } + return false; + } + + public static function QueryToArray($sSql) + { + $aData = array(); + $result = mysql_query($sSql, self::$m_resDBLink); + if (!$result) + { + throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); + } + while ($aRow = mysql_fetch_array($result, MYSQL_BOTH)) + { + $aData[] = $aRow; + } + mysql_free_result($result); + return $aData; + } + + public static function QueryToCol($sSql, $col) + { + $aColumn = array(); + $aData = self::QueryToArray($sSql); + foreach($aData as $aRow) + { + @$aColumn[] = $aRow[$col]; + } + return $aColumn; + } + + public static function ExplainQuery($sSql) + { + $aData = array(); + $result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink); + if (!$result) + { + throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); + } + + $aNames = array(); + for ($i = 0; $i < mysql_num_fields($result) ; $i++) + { + $meta = mysql_fetch_field($result, $i); + if (!$meta) + { + throw new MySQLException('mysql_fetch_field: No information available', array('query'=>$sSql, 'i'=>$i)); + } + else + { + $aNames[] = $meta->name; + } + } + + $aData[] = $aNames; + while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC)) + { + $aData[] = $aRow; + } + mysql_free_result($result); + return $aData; + } + + public static function TestQuery($sSql) + { + $result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink); + if (!$result) + { + return mysql_error(); + } + + mysql_free_result($result); + return ''; + } + + public static function NbRows($result) + { + return mysql_num_rows($result); + } + + public static function FetchArray($result) + { + return mysql_fetch_array($result, MYSQL_ASSOC); + } + + public static function Seek($result, $iRow) + { + return mysql_data_seek($result, $iRow); + } + + public static function FreeResult($result) + { + return mysql_free_result($result); + } + + public static function IsTable($sTable) + { + $aTableInfo = self::GetTableInfo($sTable); + return (!empty($aTableInfo)); + } + + public static function IsKey($sTable, $iKey) + { + $aTableInfo = self::GetTableInfo($sTable); + if (empty($aTableInfo)) return false; + if (!array_key_exists($iKey, $aTableInfo["Fields"])) return false; + $aFieldData = $aTableInfo["Fields"][$iKey]; + if (!array_key_exists("Key", $aFieldData)) return false; + return ($aFieldData["Key"] == "PRI"); + } + + public static function IsAutoIncrement($sTable, $sField) + { + $aTableInfo = self::GetTableInfo($sTable); + if (empty($aTableInfo)) return false; + if (!array_key_exists($sField, $aTableInfo["Fields"])) return false; + $aFieldData = $aTableInfo["Fields"][$sField]; + if (!array_key_exists("Extra", $aFieldData)) return false; + //MyHelpers::debug_breakpoint($aFieldData); + return (strstr($aFieldData["Extra"], "auto_increment")); + } + + public static function IsField($sTable, $sField) + { + $aTableInfo = self::GetTableInfo($sTable); + if (empty($aTableInfo)) return false; + if (!array_key_exists($sField, $aTableInfo["Fields"])) return false; + return true; + } + + public static function IsNullAllowed($sTable, $sField) + { + $aTableInfo = self::GetTableInfo($sTable); + if (empty($aTableInfo)) return false; + if (!array_key_exists($sField, $aTableInfo["Fields"])) return false; + $aFieldData = $aTableInfo["Fields"][$sField]; + return (strtolower($aFieldData["Null"]) == "yes"); + } + + // Returns an array of (fieldname => array of field info) + public static function GetTableFieldsList($sTable) + { + assert(!empty($sTable)); + + $aTableInfo = self::GetTableInfo($sTable); + if (empty($aTableInfo)) return array(); // #@# or an error ? + + return array_keys($aTableInfo["Fields"]); + } + + // Cache the information about existing tables, and their fields + private static $m_aTablesInfo = array(); + private static function _TablesInfoCacheReset() + { + self::$m_aTablesInfo = array(); + } + private static function _TablesInfoCacheInit() + { + if (!empty(self::$m_aTablesInfo)) return; + + $aTables = self::QueryToArray("SHOW TABLES FROM `".self::$m_sDBName."`", 0); + foreach ($aTables as $aTableData) + { + $sTableName = $aTableData[0]; + $aFields = self::QueryToArray("SHOW COLUMNS FROM `$sTableName`"); + // Note: without backticks, you get an error with some table names (e.g. "group") + foreach ($aFields as $aFieldData) + { + $sFieldName = $aFieldData["Field"]; + self::$m_aTablesInfo[$sTableName]["Fields"][$sFieldName] = + array + ( + "Name"=>$aFieldData["Field"], + "Type"=>$aFieldData["Type"], + "Null"=>$aFieldData["Null"], + "Key"=>$aFieldData["Key"], + "Default"=>$aFieldData["Default"], + "Extra"=>$aFieldData["Extra"] + ); + } + } + } + public static function EnumTables() + { + self::_TablesInfoCacheInit(); + return array_keys(self::$m_aTablesInfo); + } + public static function GetTableInfo($sTable) + { + self::_TablesInfoCacheInit(); + + // table names are transformed into lower case + // is that 100% specific to innodb and myISAM? + $sTableLC = strtolower($sTable); + + if (array_key_exists($sTableLC, self::$m_aTablesInfo)) return self::$m_aTablesInfo[$sTableLC]; + return null; + } +} + + +?> diff --git a/core/config.class.inc.php b/core/config.class.inc.php new file mode 100644 index 000000000..bc6402e07 --- /dev/null +++ b/core/config.class.inc.php @@ -0,0 +1,170 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class ConfigException extends CoreException +{ +} + +class Config +{ + //protected $m_bIsLoaded = false; + protected $m_sFile = ''; + + protected $m_aAppModules; + protected $m_aDataModels; + protected $m_aAddons; + + protected $m_sDBHost; + protected $m_sDBUser; + protected $m_sDBPwd; + protected $m_sDBName; + protected $m_sDBSubname; + + public function __construct($sConfigFile) + { + $this->m_sFile = $sConfigFile; + $this->Load($sConfigFile); + $this->Verify(); + } + + protected function CheckFile($sPurpose, $sFileName) + { + if (!file_exists($sFileName)) + { + throw new ConfigException("Could not find $sPurpose file", array('file' => $sFileName)); + } + } + + protected function Load($sConfigFile) + { + $this->CheckFile('configuration', $sConfigFile); + + $sConfigCode = trim(file_get_contents($sConfigFile)); + + // This does not work on several lines + // preg_match('/^<\\?php(.*)\\?'.'>$/', $sConfigCode, $aMatches)... + // So, I've implemented a solution suggested in the PHP doc (search for phpWrapper) + try + { + ob_start(); + $sCode = str_replace('<'.'?php','<'.'?', $sConfigCode); + eval('?'.'>'.trim($sCode).'<'.'?'); + $sNoise = trim(ob_get_contents()); + ob_end_clean(); + } + catch (Exception $e) + { + // well, never reach in case of parsing error :-( + // will be improved in PHP 6 ? + throw new ConfigException('Error in configuration file', array('file' => $sConfigFile, 'error' => $e->getMessage())); + } + if (strlen($sNoise) > 0) + { + // Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack) + throw new ConfigException('Syntax error in configuration file', array('file' => $sConfigFile, 'error' => $sNoise)); + } + + if (!isset($MySettings) || !is_array($MySettings)) + { + throw new ConfigException('Missing array in configuration file', array('file' => $sConfigFile, 'expected' => '$MySettings')); + } + if (!isset($MyModules) || !is_array($MyModules)) + { + throw new ConfigException('Missing item in configuration file', array('file' => $sConfigFile, 'expected' => '$MyModules')); + } + if (!array_key_exists('application', $MyModules)) + { + throw new ConfigException('Missing item in configuration file', array('file' => $sConfigFile, 'expected' => '$MyModules[\'application\']')); + } + if (!array_key_exists('business', $MyModules)) + { + throw new ConfigException('Missing item in configuration file', array('file' => $sConfigFile, 'expected' => '$MyModules[\'business\']')); + } + if (!array_key_exists('addons', $MyModules)) + { + throw new ConfigException('Missing item in configuration file', array('file' => $sConfigFile, 'expected' => '$MyModules[\'addons\']')); + } + if (!array_key_exists('user rights', $MyModules['addons'])) + { + $MyModules['addons']['user rights'] = '../addons/userrights/userrightsnull.class.inc.php'; + } + $this->m_aAppModules = $MyModules['application']; + $this->m_aDataModels = $MyModules['business']; + $this->m_aAddons = $MyModules['addons']; + + $this->m_sDBHost = trim($MySettings['db_host']); + $this->m_sDBUser = trim($MySettings['db_user']); + $this->m_sDBPwd = trim($MySettings['db_pwd']); + $this->m_sDBName = trim($MySettings['db_name']); + $this->m_sDBSubname = trim($MySettings['db_subname']); + } + + protected function Verify() + { + foreach ($this->m_aAppModules as $sModule => $sToInclude) + { + $this->CheckFile('application module', $sToInclude); + } + foreach ($this->m_aDataModels as $sModule => $sToInclude) + { + $this->CheckFile('business model', $sToInclude); + } + foreach ($this->m_aAddons as $sModule => $sToInclude) + { + $this->CheckFile('addon module', $sToInclude); + } + } + + public function GetAppModules() + { + return $this->m_aAppModules; + } + + public function GetDataModels() + { + return $this->m_aDataModels; + } + + public function GetAddons() + { + return $this->m_aAddons; + } + + public function GetDBHost() + { + return $this->m_sDBHost; + } + + + public function GetDBName() + { + return $this->m_sDBName; + } + + public function GetDBSubname() + { + return $this->m_sDBSubname; + } + + public function GetDBUser() + { + return $this->m_sDBUser; + } + + public function GetDBPwd() + { + return $this->m_sDBPwd; + } +} +?> diff --git a/core/coreexception.class.inc.php b/core/coreexception.class.inc.php new file mode 100644 index 000000000..d720fc419 --- /dev/null +++ b/core/coreexception.class.inc.php @@ -0,0 +1,52 @@ +m_sIssue = $sIssue; + $this->m_sImpact = $sImpact; + $this->m_aContextData = $aContextData ? $aContextData : array(); + + $sMessage = $sIssue; + if (!empty($sImpact)) $sMessage .= "($sImpact)"; + if (count($this->m_aContextData) > 0) + { + $sMessage .= ": "; + $aContextItems = array(); + foreach($this->m_aContextData as $sKey => $value) + { + if (is_array($value)) + { + $aPairs = array(); + foreach($value as $key => $val) + { + if (is_array($val)) + { + $aPairs[$key] = '('.implode(', ', $val).')'; + } + else + { + $aPairs[$key] = $val; + } + } + $sValue = '{'.implode('; ', $aPairs).'}'; + } + else + { + $sValue = $value; + } + $aContextItems[] = "$sKey = $sValue"; + } + $sMessage .= implode(', ', $aContextItems); + } + parent::__construct($sMessage, 0); + } + + public function getHtmlDesc($sHighlightHtmlBegin = '', $sHighlightHtmlEnd = '') + { + return $this->getMessage(); + } +} + +?> diff --git a/core/data.generator.class.inc.php b/core/data.generator.class.inc.php new file mode 100644 index 000000000..f9d284e3e --- /dev/null +++ b/core/data.generator.class.inc.php @@ -0,0 +1,362 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +/** + * Data Generator helper class + * + * This class is useful to generate a lot of sample data that look consistent + * for a given organization in order to simulate a real CMDB + */ +class cmdbDataGenerator +{ + protected $m_sOrganizationKey; + protected $m_sOrganizationCode; + protected $m_sOrganizationName; + protected $m_OrganizationDomains; + + /** + * Constructor + */ + public function __construct($sOrganizationId = "") + { + global $aCompanies, $aCompaniesCode; + if ($sOrganizationId == '') + { + // No organization provided, pick a random and unused one from our predefined list + $retries = 5*count($aCompanies); + while ( ($retries > 0) && !isset($this->m_sOrganizationCode)) // Stupid algorithm, but I'm too lazy to do something bulletproof tonight + { + $index = rand(0, count($aCompanies) - 1); + if (!$this->OrganizationExists($aCompanies[$index]['code'])) + { + $this->m_sOrganizationCode = $aCompanies[$index]['code']; + $this->m_sOrganizationName = $aCompanies[$index]['name']; + $this->m_OrganizationDomains = $aCompanies[$index]['domain']; + } + $retries--; + } + } + else + { + // A code has been provided, let's take the information we need from the organization itself + $this->m_sOrganizationId = $sOrganizationId; + $oOrg = $this->GetOrganization($sOrganizationId); + if ($oOrg == null) + { + echo "Unable to find the organization '$sOrganisationCode' in the database... can not add objects into this organization.
\n"; + exit(); + } + $this->m_sOrganizationCode = $oOrg->Get('code'); + $this->m_sOrganizationName = $oOrg->Get('name'); + if (!isset($aCompaniesCode[$this->m_sOrganizationCode]['domain'])) + { + // Generate some probable domain names for this organization + $this->m_OrganizationDomains = array(strtolower($this->m_sOrganizationCode).".com", strtolower($this->m_sOrganizationCode).".org", strtolower($this->m_sOrganizationCode)."corp.net",); + } + else + { + // Pick the domain names for this organization from the predefined list + $this->m_OrganizationDomains = $aCompaniesCode[$this->m_sOrganizationCode]['domain']; + } + } + + if (!isset($this->m_sOrganizationCode)) + { + echo "Unable to find an organization code which is not already used... can not create a new organization. Enhance the list of fake organizations (\$aCompanies in data_sample.inc.php).
\n"; + exit(); + } + } + + /** + * Get the current organization id used by the generator + * + * @return string The organization id + */ + public function GetOrganizationId() + { + return $this->m_sOrganizationId; + } + + /** + * Get the current organization id used by the generator + * + * @param string The organization id + * @return none + */ + public function SetOrganizationId($sId) + { + $this->m_sOrganizationId = $sId; + } + + /** + * Get the current organization code used by the generator + * + * @return string The organization code + */ + public function GetOrganizationCode() + { + return $this->m_sOrganizationCode; + } + + /** + * Get the current organization name used by the generator + * + * @return string The organization name + */ + function GetOrganizationName() + { + return $this->m_sOrganizationName; + } + + /** + * Get a pseudo random first name taken from a (big) prefedined list + * + * @return string A random first name + */ + function GenerateFirstName() + { + global $aFirstNames; + return $aFirstNames[rand(0, count($aFirstNames) - 1)]; + } + + /** + * Get a pseudo random last name taken from a (big) prefedined list + * + * @return string A random last name + */ + function GenerateLastName() + { + global $aNames; + return $aNames[rand(0, count($aNames) - 1)]; + } + + /** + * Get a pseudo random country name taken from a prefedined list + * + * @return string A random city name + */ + function GenerateCountryName() + { + global $aCountries; + return $aCountries[rand(0, count($aCountries) - 1)]; + } + + /** + * Get a pseudo random city name taken from a (big) prefedined list + * + * @return string A random city name + */ + function GenerateCityName() + { + global $aCities; + return $aCities[rand(0, count($aCities) - 1)]; + } + + /** + * Get a pseudo random email address made of the first name, last name and organization's domain + * + * @return string A random email address + */ + function GenerateEmail($sFirstName, $sLastName) + { + if (rand(1, 20) > 18) + { + // some people (let's say 5~10%) have an irregular email address + $sEmail = strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain()); + } + else + { + $sEmail = strtolower($this->CleanForEmail($sFirstName)).".".strtolower($this->CleanForEmail($sLastName))."@".strtolower($this->GenerateDomain()); + } + return $sEmail; + } + + /** + * Generate (pseudo) random strings that follow a given pattern + * + * The template is made of any number of 'parts' separated by pipes '|' + * Each part is either: + * - domain() => returns a domain name for the current organization + * - enum(aaa,bb,c,dddd) => returns randomly one of aaa,bb,c or dddd with the same + * probability of occurence. If you want to change the probability you can repeat some values + * i.e enum(most probable,most probable,most probable,most probable,most probable,rare) + * - number(xxx-yyy) => a random number between xxx and yyy (bounds included) + * note that if the first number (xxx) begins with a zero, then the result will zero padded + * to the same number of digits as xxx. + * All other 'part' that does not follow one of the above mentioned pattern is returned as is + * + * Example: GenerateString("enum(sw,rtr,gw)|number(00-99)|.|domain()") + * will produce strings like "sw01.netcmdb.com" or "rtr45.itop.org" + * + * @param string $sTemplate The template used for generating the string + * @return string The generated pseudo random the string + */ + function GenerateString($sTemplate) + { + $sResult = ""; + $aParts = split("\|", $sTemplate); + foreach($aParts as $sPart) + { + if (preg_match("/domain\(\)/", $sPart, $aMatches)) + { + $sResult .= strtolower($this->GenerateDomain()); + } + elseif (preg_match("/enum\((.+)\)/", $sPart, $aMatches)) + { + $sEnumValues = $aMatches[1]; + $aEnumValues = split(",", $sEnumValues); + $sResult .= $aEnumValues[rand(0, count($aEnumValues) - 1)]; + } + elseif (preg_match("/number\((\d+)-(\d+)\)/", $sPart, $aMatches)) + { + $sStartNumber = $aMatches[1]; + if ($sStartNumber[0] == '0') + { + // number must be zero padded + $sFormat = "%0".strlen($sStartNumber)."d"; + } + else + { + $sFormat = "%d"; + } + $sEndNumber = $aMatches[2]; + $sResult .= sprintf($sFormat, rand($sStartNumber, $sEndNumber)); + } + else + { + $sResult .= $sPart; + } + } + return $sResult; + } + + /** + * Generate a foreign key by picking a random element of the given class in a set limited by the given search criteria + * + * Example: GenerateKey("bizLocation", array('org_id', $oGenerator->GetOrganizationId()); + * will produce the foreign key of a Location object picked at random in the same organization + * + * @param string $sClass The name of the class to search for + * @param string $aFilterCriteria A hash array of filterCOde => FilterValue (the strict operator '=' is used ) + * @return mixed The key to an object of the given class, or null if none are found + */ + function GenerateKey($sClass, $aFilterCriteria) + { + $retKey = null; + $oFilter = new CMDBSearchFilter($sClass); + foreach($aFilterCriteria as $sFilterCode => $filterValue) + { + $oFilter->AddCondition($sFilterCode, $filterValue, '='); + } + $oSet = new CMDBObjectSet($oFilter); + if ($oSet->Count() > 0) + { + $max_count = $index = rand(1, $oSet->Count()); + do + { + $oObj = $oSet->Fetch(); + $index--; + } + while($index > 0); + + if (!is_object($oObj)) + { + echo "
";
+				echo "ERROR: non empty set, but invalid object picked! class='$sClass'\n";
+				echo "Index chosen: $max_count\n";
+				echo "The set is supposed to contain ".$oSet->Count()." object(s)\n";
+				echo "Filter criteria:\n";
+				print_r($aFilterCriteria);
+				echo "
"; + } + else + { + $retKey = $oObj->GetKey(); + } + } + return $retKey; + } + /////////////////////////////////////////////////////////////////////////////// + // + // Protected methods + // + /////////////////////////////////////////////////////////////////////////////// + + /** + * Generate a (random) domain name consistent with the organization name & code + * + * The values are pulled from a (limited) predefined list. Note that a given + * organization may have several domain names, so the result may be random + * + * @return string A domain name (like netcnmdb.com) + */ + protected function GenerateDomain() + { + if (is_array($this->m_OrganizationDomains)) + { + $sDomain = $this->m_OrganizationDomains[rand(0, count($this->m_OrganizationDomains)-1)]; + } + else + { + $sDomain = $this->m_OrganizationDomains; + } + return $sDomain; + } + + /** + * Strips accented characters from a string in order to produce a suitable email address + * + * @param string The text string to clean + * @return string The cleanified text string + */ + protected function CleanForEmail($sText) + { + return str_replace(array("'", "é", "è", "ê", "ç", "à", "â", "ñ", "ö", "ä"), array("", "e", "e", "e", "c", "a", "a", "n", "oe", "ae"), $sText); + } + + /** + * Check if an organization with the given code already exists in the database + * + * @param string $sCode The code to look for + * @return boolean true if the given organization exists, false otherwise + */ + protected function OrganizationExists($sCode) + { + $oFilter = new CMDBSearchFilter('bizOrganization'); + $oFilter->AddCondition('code', $sCode, '='); + $oSet = new CMDBObjectSet($oFilter); + return ($oSet->Count() > 0); + } + + /** + * Search for an organization with the given code in the database + * + * @param string $Id The organization Id to look for + * @return cmdbOrganization the organization if it exists, null otherwise + */ + protected function GetOrganization($sId) + { + $oOrg = null; + $oFilter = new CMDBSearchFilter('bizOrganization'); + $oFilter->AddCondition('pkey', $sId, '='); + $oSet = new CMDBObjectSet($oFilter); + if ($oSet->Count() > 0) + { + $oOrg = $oSet->Fetch(); // Let's take the first one found + } + return $oOrg; + } +} +?> diff --git a/core/dbobject.class.php b/core/dbobject.class.php new file mode 100644 index 000000000..f96b4cf2f --- /dev/null +++ b/core/dbobject.class.php @@ -0,0 +1,791 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +require_once('metamodel.class.php'); + + +/** + * A persistent object, as defined by the metamodel + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class DBObject +{ + private static $m_aMemoryObjectsByClass = array(); + + private $m_bIsInDB = false; // true IIF the object is mapped to a DB record + private $m_iKey = null; + private $m_aCurrValues = array(); + private $m_aOrigValues = array(); + + private $m_bFullyLoaded = false; // Compound objects can be partially loaded + private $m_aLoadedAtt = array(); // Compound objects can be partially loaded, array of sAttCode + + // Use the MetaModel::NewObject to build an object (do we have to force it?) + public function __construct($aRow = null) + { + if (!empty($aRow)) + { + $this->FromRow($aRow); + $this->m_bFullyLoaded = $this->IsFullyLoaded(); + return; + } + // Creation of brand new object + // + + $this->m_iKey = self::GetNextTempId(get_class($this)); + + // set default values + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + $this->m_aOrigValues[$sAttCode] = null; + // ??? $this->m_aLoadedAtt[$sAttCode] = true; + } + } + + // Returns an Id for memory objects + static protected function GetNextTempId($sClass) + { + if (!array_key_exists($sClass, self::$m_aMemoryObjectsByClass)) + { + self::$m_aMemoryObjectsByClass[$sClass] = 0; + } + self::$m_aMemoryObjectsByClass[$sClass]++; + return (- self::$m_aMemoryObjectsByClass[$sClass]); + } + + public function __toString() + { + $sRet = ''; + $sClass = get_class($this); + $sRootClass = MetaModel::GetRootClass($sClass); + $iPKey = $this->GetKey(); + $sRet .= "$sClass::$iPKey
\n"; + $sRet .= "
    \n"; + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + $sRet .= "
  • ".$oAttDef->GetLabel()." = ".$this->GetAsHtml($sAttCode)."
  • \n"; + } + $sRet .= "
"; + return $sRet; + } + + // Restore initial values... mmmm, to be discussed + public function DBRevert() + { + $this->Reload(); + } + + protected function IsFullyLoaded() + { + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + @$bIsLoaded = $this->m_aLoadedAtt[$sAttCode]; + if ($bIsLoaded !== true) + { + return false; + } + } + return true; + } + + protected function Reload() + { + assert($this->m_bIsInDB); + $aRow = MetaModel::MakeSingleRow(get_class($this), $this->m_iKey); + if (empty($aRow)) + { + trigger_error("Failed to reload object of class '".get_class($this)."', pkey = ".$this->m_iKey, E_USER_ERROR); + } + $this->FromRow($aRow); + + // Process linked set attributes + // + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + if (!$oAttDef->IsLinkSet()) continue; + + // Load the link information + $sLinkClass = $oAttDef->GetLinkedClass(); + $sExtKeyToMe = $oAttDef->GetExtKeyToMe(); + + // The class to target is not the current class, because if this is a derived class, + // it may differ from the target class, then things start to become confusing + $oRemoteExtKeyAtt = MetaModel::GetAttributeDef($sLinkClass, $sExtKeyToMe); + $sMyClass = $oRemoteExtKeyAtt->GetTargetClass(); + + $oMyselfSearch = new DBObjectSearch($sMyClass); + $oMyselfSearch->AddCondition('pkey', $this->m_iKey, '='); + + $oLinkSearch = new DBObjectSearch($sLinkClass); + $oLinkSearch->AddCondition_PointingTo($oMyselfSearch, $sExtKeyToMe); + $oLinks = new DBObjectSet($oLinkSearch); + + $this->m_aCurrValues[$sAttCode] = $oLinks; + $this->m_aOrigValues[$sAttCode] = clone $this->m_aCurrValues[$sAttCode]; + $this->m_aLoadedAtt[$sAttCode] = true; + } + + $this->m_bFullyLoaded = true; + } + + protected function FromRow($aRow) + { + $this->m_iKey = null; + $this->m_bIsInDB = true; + $this->m_aCurrValues = array(); + $this->m_aOrigValues = array(); + $this->m_aLoadedAtt = array(); + + // Get the key + // + $sKeyField = "pkey"; + if (!array_key_exists($sKeyField, $aRow)) + { + // #@# Bug ? + trigger_error("Missing key for class '".get_class($this)."'", E_USER_ERROR); + } + else + { + $iPKey = $aRow[$sKeyField]; + if (!self::IsValidPKey($iPKey)) + { + trigger_error("An object PKey must be an integer value ($iPKey)", E_USER_NOTICE); + } + $this->m_iKey = $iPKey; + } + + // Build the object from an array of "attCode"=>"value") + // + $bFullyLoaded = true; // ... set to false if any attribute is not found + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + // Say something, whatever the type of attribute + $this->m_aLoadedAtt[$sAttCode] = false; + + // Skip links (could not be loaded by the mean of this query) + if ($oAttDef->IsLinkSet()) continue; + + if (array_key_exists($sAttCode, $aRow)) + { + $sValue = $oAttDef->SQLValueToRealValue($aRow[$sAttCode]); + $this->m_aCurrValues[$sAttCode] = $sValue; + $this->m_aOrigValues[$sAttCode] = $sValue; + $this->m_aLoadedAtt[$sAttCode] = true; + } + else + { + // This attribute was expected and not found in the query columns + $bFullyLoaded = false; + } + } + return $bFullyLoaded; + } + + public function Set($sAttCode, $value) + { + if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this)))) + { + trigger_error("Unknown attribute code '$sAttCode' for the class ".get_class($this), E_USER_ERROR); + } + $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + if ($this->m_bIsInDB && !$this->m_bFullyLoaded) + { + // First time Set is called... ensure that the object gets fully loaded + // Otherwise we would lose the values on a further Reload + // + consistency does not make sense ! + $this->Reload(); + } + if($oAttDef->IsScalar() && !$oAttDef->IsNullAllowed() && is_null($value)) + { + trigger_error("null not allowed for attribute '$sAttCode', setting default value", E_USER_NOTICE); + $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + return; + } + if ($oAttDef->IsExternalKey() && is_object($value)) + { + // Setting an external key with a whole object (instead of just an ID) + // let's initialize also the external fields that depend on it + // (useful when building objects in memory and not from a query) + if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass()))) + { + trigger_error("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored", E_USER_NOTICE); + $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + } + else + { + $this->m_aCurrValues[$sAttCode] = $value->GetKey(); + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef) + { + if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode)) + { + $this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode()); + } + } + } + return; + } + if(!$oAttDef->IsScalar() && !is_object($value)) + { + trigger_error("scalar not allowed for attribute '$sAttCode', setting default value (empty list)", E_USER_NOTICE); + $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + return; + } + if($oAttDef->IsLinkSet()) + { + if((get_class($value) != 'DBObjectSet') && !is_subclass_of($value, 'DBObjectSet')) + { + trigger_error("expecting a set of persistent objects (found a '".get_class($value)."'), setting default value (empty list)", E_USER_NOTICE); + $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + return; + } + + $oObjectSet = $value; + $sSetClass = $oObjectSet->GetClass(); + $sLinkClass = $oAttDef->GetLinkedClass(); + // not working fine :-( if (!is_subclass_of($sSetClass, $sLinkClass)) + if ($sSetClass != $sLinkClass) + { + trigger_error("expecting a set of '$sLinkClass' objects (found a set of '$sSetClass'), setting default value (empty list)", E_USER_NOTICE); + $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + return; + } + } + $this->m_aCurrValues[$sAttCode] = $oAttDef->MakeRealValue($value); + } + + public function Get($sAttCode) + { + if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this)))) + { + trigger_error("Unknown attribute code '$sAttCode' for the class ".get_class($this), E_USER_ERROR); + } + if ($this->m_bIsInDB && !$this->m_aLoadedAtt[$sAttCode]) + { + // #@# non-scalar attributes.... handle that differentely + $this->Reload(); + } + $this->ComputeFields(); + return $this->m_aCurrValues[$sAttCode]; + } + + public function ComputeFields() + { + if (is_callable(array($this, 'ComputeValues'))) + { + // First check that we are not currently computing the fields + // (yes, we need to do some things like Set/Get to compute the fields which will in turn trigger the update...) + foreach (debug_backtrace() as $aCallInfo) + { + if (!array_key_exists("class", $aCallInfo)) continue; + if ($aCallInfo["class"] != get_class($this)) continue; + if ($aCallInfo["function"] != "ComputeValues") continue; + return; //skip! + } + + $this->ComputeValues(); + } + } + + public function GetHyperLink($sLabel = "") + { + if (empty($sLabel)) + { + $sLabel = $this->GetName(); + } + $aAvailableFields = array($sLabel); + return call_user_func(array(get_class($this), 'MakeHyperLink'), get_class($this), $this->GetKey(), $aAvailableFields); + } + + public function GetAsHTML($sAttCode) + { + $sClass = get_class($this); + $oAtt = MetaModel::GetAttributeDef($sClass, $sAttCode); + + $aExtKeyFriends = MetaModel::GetExtKeyFriends($sClass, $sAttCode); + if (count($aExtKeyFriends) > 0) + { + // This attribute is an ext key (in this class or in another class) + // The corresponding value is an id of the remote object + // Let's try to use the corresponding external fields for a sexy display + + $aAvailableFields = array(); + foreach ($aExtKeyFriends as $sDispAttCode => $oExtField) + { + $aAvailableFields[$oExtField->GetExtAttCode()] = $oExtField->GetAsHTML($this->Get($oExtField->GetCode())); + } + + $sTargetClass = $oAtt->GetTargetClass(EXTKEY_ABSOLUTE); + return call_user_func(array(get_class($this), 'MakeHyperLink'), $sTargetClass, $this->Get($sAttCode), $aAvailableFields); + } + + // That's a standard attribute (might be an ext field or a direct field, etc.) + return $oAtt->GetAsHTML($this->Get($sAttCode)); + } + + public function GetAsXML($sAttCode) + { + $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + return $oAtt->GetAsXML($this->Get($sAttCode)); + } + + public function GetAsCSV($sAttCode, $sSeparator = ';', $sSepEscape = ',') + { + $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sSepEscape); + } + + // could be in the metamodel ? + public static function IsValidPKey($value) + { + return ((string)$value === (string)(int)$value); + } + + public function GetKey() + { + return $this->m_iKey; + } + public function SetKey($iNewKey) + { + if (!self::IsValidPKey($iNewKey)) + { + trigger_error("An object PKey must be an integer value ($iNewKey)", E_USER_ERROR); + } + + if ($this->m_bIsInDB && !empty($this->m_iKey) && ($this->m_iKey != $iNewKey)) + { + trigger_error("Changing the key ({$this->m_iKey} to $iNewKey) on an object (class {".get_class($this).") wich already exists in the Database", E_USER_NOTICE); + } + $this->m_iKey = $iNewKey; + } + + public function GetName() + { + $sNameAttCode = MetaModel::GetNameAttributeCode(get_class($this)); + if (empty($sNameAttCode)) + { + return $this->m_iKey; + } + else + { + return $this->Get($sNameAttCode); + } + } + + public function GetState() + { + $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); + if (empty($sStateAttCode)) + { + return ''; + } + else + { + $aStates = MetaModel::EnumStates(get_class($this)); + return $aStates[$this->Get($sStateAttCode)]['label']; + } + } + + /** + * Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...) + * for the given attribute in the current state of the object + * @param string $sAttCode The code of the attribute + * @return integer Flags: the binary combination of the flags applicable to this attribute + */ + public function GetAttributeFlags($sAttCode) + { + $iFlags = 0; // By default (if no life cycle) no flag at all + $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); + if (!empty($sStateAttCode)) + { + $iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode); + } + return $iFlags; + } + + // check if the given (or current) value is suitable for the attribute + public function CheckValue($sAttCode, $value = null) + { + $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + if ($oAtt->IsExternalKey()) + { + if (!$oAtt->IsNullAllowed() || ($this->Get($sAttCode) != 0) ) + { + $oTargetObj = MetaModel::GetObject($oAtt->GetTargetClass(), $this->Get($sAttCode)); + if (!$oTargetObj) + { + echo "Invalid value (".$this->Get($sAttCode).") for ExtKey $sAttCode."; + return false; + } + } + } + return true; + } + + // check attributes together + public function CheckConsistency() + { + return true; + } + + // check if it is allowed to record the new object into the database + // a displayable error is returned + // Note: checks the values and consistency + public function CheckToInsert() + { + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + if (!$this->CheckValue($sAttCode)) return false; + } + if (!$this->CheckConsistency()) return false; + return true; + } + + // check if it is allowed to update the existing object into the database + // a displayable error is returned + // Note: checks the values and consistency + public function CheckToUpdate() + { + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + if (!$this->CheckValue($sAttCode)) return false; + } + if (!$this->CheckConsistency()) return false; + return true; + } + + // check if it is allowed to delete the existing object from the database + // a displayable error is returned + public function CheckToDelete() + { + return true; + } + + protected function ListChangedValues(array $aProposal) + { + $aDelta = array(); + foreach ($aProposal as $sAtt => $proposedValue) + { + if (!array_key_exists($sAtt, $this->m_aOrigValues) || ($this->m_aOrigValues[$sAtt] != $proposedValue)) + { + $aDelta[$sAtt] = $proposedValue; + } + } + return $aDelta; + } + + // List the attributes that have been changed + // Returns an array of attname => currentvalue + public function ListChanges() + { + return $this->ListChangedValues($this->m_aCurrValues); + } + + // used both by insert/update + private function DBWriteLinks() + { + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + { + if (!$oAttDef->IsLinkSet()) continue; + + $oLinks = $this->Get($sAttCode); + $oLinks->Rewind(); + while ($oLinkedObject = $oLinks->Fetch()) + { + $oLinkedObject->Set($oAttDef->GetExtKeyToMe(), $this->m_iKey); + $oLinkedObject->DBWrite(); + } + + // Delete the objects that were initialy present and disappeared from the list + // (if any) + $oOriginalSet = $this->m_aOrigValues[$sAttCode]; + if ($oOriginalSet != null) + { + $aOriginalList = $oOriginalSet->ToArray(); + $aNewSet = $oLinks->ToArray(); + $aToDelete = array_diff($aOriginalList, $aNewSet); + foreach ($aToDelete as $iKey => $oObject) + { + $oObject->DBDelete(); + } + } + } + } + + private function DBInsertSingleTable($sTableClass) + { + $sClass = get_class($this); + + // fields in first array, values in the second + $aFieldsToWrite = array(); + $aValuesToWrite = array(); + + if (!empty($this->m_iKey) && ($this->m_iKey >= 0)) + { + // Add it to the list of fields to write + $aFieldsToWrite[] = MetaModel::DBGetKey($sTableClass); + $aValuesToWrite[] = CMDBSource::Quote($this->m_iKey); + } + + foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) + { + // Skip this attribute if not defined in this table + if (!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode)) continue; + if ($oAttDef->IsDirectField()) + { + $aFieldsToWrite[] = $oAttDef->GetSQLExpr(); + $aValuesToWrite[] = CMDBSource::Quote($oAttDef->RealValueToSQLValue($this->m_aCurrValues[$sAttCode])); + } + } + + if (count($aValuesToWrite) == 0) return false; + + $sTable = MetaModel::DBGetTable($sTableClass); + $sInsertSQL = "INSERT INTO $sTable (".join(",", $aFieldsToWrite).") VALUES (".join(", ", $aValuesToWrite).")"; + + $iNewKey = CMDBSource::InsertInto($sInsertSQL); + // Note that it is possible to have a key defined here, and the autoincrement expected, this is acceptable in a non root class + if (empty($this->m_iKey)) + { + // Take the autonumber + $this->m_iKey = $iNewKey; + } + return $this->m_iKey; + } + + // Insert of record for the new object into the database + // Returns the key of the newly created object + public function DBInsert() + { + if ($this->m_bIsInDB) + { + trigger_error("The object already exists into the Database, you may want to use the clone function", E_USER_ERROR); + } + + $sClass = get_class($this); + $sRootClass = MetaModel::GetRootClass($sClass); + + // Ensure the update of the values (we are accessing the data directly) + $this->ComputeFields(); + + if ($this->m_iKey < 0) + { + // This was a temporary "memory" key: discard it so that DBInsertSingleTable will not try to use it! + $this->m_iKey = null; + } + + // If not automatically computed, then check that the key is given by the caller + if (!MetaModel::IsAutoIncrementKey($sRootClass)) + { + if (empty($this->m_iKey)) + { + trigger_error("Missing key for the object to write - This class is supposed to have a user defined key, not an autonumber", E_USER_NOTICE); + } + } + + // First query built upon on the root class, because the ID must be created first + $this->m_iKey = $this->DBInsertSingleTable($sRootClass); + + // Then do the leaf class, if different from the root class + if ($sClass != $sRootClass) + { + $this->DBInsertSingleTable($sClass); + } + + // Then do the other classes + foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass) + { + if ($sParentClass == $sRootClass) continue; + if (MetaModel::DBGetTable($sParentClass) == "") continue; + $this->DBInsertSingleTable($sParentClass); + } + + $this->DBWriteLinks(); + + // Reload to update the external attributes + $this->m_bIsInDB = true; + $this->Reload(); + return $this->m_iKey; + } + + // Creates a copy of the current object into the database + // Returns the id of the newly created object + public function DBClone($iNewKey = null) + { + $this->m_bIsInDB = false; + $this->m_iKey = $iNewKey; + return $this->DBInsert(); + } + + // Update a record + public function DBUpdate() + { + if (!$this->m_bIsInDB) + { + trigger_error("DBUpdate: could not update a newly created object, please call DBInsert instead", E_USER_ERROR); + } + $aChanges = $this->ListChanges(); + if (count($aChanges) == 0) + { + trigger_error("Attempting to update an unchanged object", E_USER_NOTICE); + return; + } + $bHasANewExternalKeyValue = false; + foreach($aChanges as $sAttCode => $valuecurr) + { + $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + if ($oAttDef->IsExternalKey()) $bHasANewExternalKeyValue = true; + if (!$oAttDef->IsDirectField()) unset($aChanges[$sAttCode]); + } + + // Update scalar attributes + if (count($aChanges) != 0) + { + $oFilter = new DBObjectSearch(get_class($this)); + $oFilter->AddCondition('pkey', $this->m_iKey, '='); + + $sSQL = MetaModel::MakeUpdateQuery($oFilter, $aChanges); + CMDBSource::Query($sSQL); + } + + $this->DBWriteLinks(); + + // Reload to get the external attributes + if ($bHasANewExternalKeyValue) $this->Reload(); + + return $this->m_iKey; + } + + // Make the current changes persistent - clever wrapper for Insert or Update + public function DBWrite() + { + if ($this->m_bIsInDB) + { + return $this->DBUpdate(); + } + else + { + return $this->DBInsert(); + } + } + + // Delete a record + public function DBDelete() + { + $oFilter = new DBObjectSearch(get_class($this)); + $oFilter->AddCondition('pkey', $this->m_iKey, '='); + + $sSQL = MetaModel::MakeDeleteQuery($oFilter); + CMDBSource::Query($sSQL); + + $this->m_bIsInDB = false; + $this->m_iKey = null; + } + + public function EnumTransitions() + { + $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); + if (empty($sStateAttCode)) return array(); + + $sState = $this->Get(MetaModel::GetStateAttributeCode(get_class($this))); + return MetaModel::EnumTransitions(get_class($this), $sState); + } + + public function ApplyStimulus($sStimulusCode) + { + $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); + if (empty($sStateAttCode)) return false; + + MyHelpers::CheckKeyInArray('object lifecycle stimulus', $sStimulusCode, MetaModel::EnumStimuli(get_class($this))); + + $aStateTransitions = $this->EnumTransitions(); + $aTransitionDef = $aStateTransitions[$sStimulusCode]; + + // Change the state before proceeding to the actions, this is necessary because an action might + // trigger another stimuli (alternative: push the stimuli into a queue) + $this->Set($sStateAttCode, $aTransitionDef['target_state']); + + // $aTransitionDef is an + // array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD + + $bSuccess = true; + foreach ($aTransitionDef['actions'] as $sActionHandler) + { + // std PHP spec + $aActionCallSpec = array($this, $sActionHandler); + + if (!is_callable($aActionCallSpec)) + { + trigger_error("Unable to call action: ".get_class($this)."::$sActionHandler", E_USER_ERROR); + return; + } + $bRet = call_user_func($aActionCallSpec, $sStimulusCode); + // if one call fails, the whole is considered as failed + if (!$bRet) $bSuccess = false; + } + + return $bSuccess; + } + + // Return an empty set for the parent of all + public static function GetRelationQueries($sRelCode) + { + return array(); + } + + public function GetRelatedObjects($sRelCode, $iMaxDepth = 99, &$aResults = array()) + { + foreach (MetaModel::EnumRelationQueries(get_class($this), $sRelCode) as $sDummy => $aQueryInfo) + { + MetaModel::DbgTrace("object=".$this->GetKey().", depth=$iMaxDepth, rel=".$aQueryInfo["sQuery"]); + $sQuery = $aQueryInfo["sQuery"]; + $bPropagate = $aQueryInfo["bPropagate"]; + $iDistance = $aQueryInfo["iDistance"]; + + $iDepth = $bPropagate ? $iMaxDepth - 1 : 0; + + $oFlt = DBObjectSearch::FromSibusQL($sQuery, array(), $this); + $oObjSet = new DBObjectSet($oFlt); + while ($oObj = $oObjSet->Fetch()) + { + $sRootClass = MetaModel::GetRootClass(get_class($oObj)); + $sObjKey = $oObj->GetKey(); + if (array_key_exists($sRootClass, $aResults)) + { + if (array_key_exists($sObjKey, $aResults[$sRootClass])) + { + continue; // already visited, skip + } + } + + $aResults[$sRootClass][$sObjKey] = $oObj; + if ($iDepth > 0) + { + $oObj->GetRelatedObjects($sRelCode, $iDepth, $aResults); + } + } + } + return $aResults; + } +} + + +?> diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php new file mode 100644 index 000000000..45afef985 --- /dev/null +++ b/core/dbobjectsearch.class.php @@ -0,0 +1,967 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + + +/** + * Sibusql - value set start + * @package iTopORM + * @info zis is private + */ +define('VS_START', '{'); +/** + * Sibusql - value set end + * @package iTopORM + */ +define('VS_END', '}'); + + +define('SIBUSQLPARAMREGEXP', "/\\$\\[(.*)\\:(.*)\\:(.*)\\]/U"); +define('SIBUSQLTHISREGEXP', "/this\\.(.*)/U"); + + +/** + * Define filters for a given class of objects (formerly named "filter") + * + * @package iTopORM + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @mytagrom youpi + * @since 1.0 + * @version 1.1.1.1 $ + */ +class DBObjectSearch +{ + private $m_sClass; + private $m_sClassAlias; + private $m_aClasses; // queried classes (alias => class name) + private $m_oSearchCondition; + private $m_aFullText; + private $m_aPointingTo; + private $m_aReferencedBy; + private $m_aRelatedTo; + + public function __construct($sClass, $sClassAlias = '') + { + if (empty($sClassAlias)) $sClassAlias = $sClass; + assert('is_string($sClass)'); + assert('MetaModel::IsValidClass($sClass)'); // #@# could do better than an assert, or at least give the caller's reference + // => idee d'un assert avec call stack (autre utilisation = echec sur query SQL) + if (empty($sClassAlias)) $sClassAlias = $sClass; + $this->m_sClass = $sClass; + $this->m_sClassAlias = $sClassAlias; + $this->m_aClasses = array($sClassAlias => $sClass); + $this->m_oSearchCondition = new TrueExpression; + $this->m_aFullText = array(); + $this->m_aPointingTo = array(); + $this->m_aReferencedBy = array(); + $this->m_aRelatedTo = array(); + } + + public function IsAny() + { + // #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false; + if (count($this->m_aFullText) > 0) return false; + if (count($this->m_aPointingTo) > 0) return false; + if (count($this->m_aReferencedBy) > 0) return false; + if (count($this->m_aRelatedTo) > 0) return false; + return true; + } + + public function Describe() + { + // To replace __Describe + } + + public function DescribeConditionPointTo($sExtKeyAttCode) + { + if (!isset($this->m_aPointingTo[$sExtKeyAttCode])) return ""; + $oFilter = $this->m_aPointingTo[$sExtKeyAttCode]; + if ($oFilter->IsAny()) return ""; + $oAtt = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode); + return $oAtt->GetLabel()." having ({$oFilter->DescribeConditions()})"; + } + + public function DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode) + { + if (!isset($this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode])) return ""; + $oFilter = $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]; + if ($oFilter->IsAny()) return ""; + $oAtt = MetaModel::GetAttributeDef($sForeignClass, $sForeignExtKeyAttCode); + return "being ".$oAtt->GetLabel()." for ".$sForeignClass."s in ({$oFilter->DescribeConditions()})"; + } + + public function DescribeConditionRelTo($aRelInfo) + { + $oFilter = $aRelInfo['flt']; + $sRelCode = $aRelInfo['relcode']; + $iMaxDepth = $aRelInfo['maxdepth']; + return "related ($sRelCode... peut mieux faire !, $iMaxDepth dig depth) to a {$oFilter->GetClass()} ({$oFilter->DescribeConditions()})"; + } + + public function DescribeConditions() + { + $aConditions = array(); + + $aCondFT = array(); + foreach($this->m_aFullText as $sFullText) + { + $aCondFT[] = " contain word(s) '$sFullText'"; + } + if (count($aCondFT) > 0) + { + $aConditions[] = "which ".implode(" and ", $aCondFT); + } + + // #@# todo - review textual description of the JOIN and search condition (is that still feasible?) + $aConditions[] = $this->RenderCondition(); + + $aCondPoint = array(); + foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter) + { + if ($oFilter->IsAny()) continue; + $aCondPoint[] = $this->DescribeConditionPointTo($sExtKeyAttCode); + } + if (count($aCondPoint) > 0) + { + $aConditions[] = implode(" and ", $aCondPoint); + } + + $aCondReferred= array(); + foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences) + { + foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter) + { + if ($oForeignFilter->IsAny()) continue; + $aCondReferred[] = $this->DescribeConditionRefBy($sForeignClass, $sForeignExtKeyAttCode); + } + } + foreach ($this->m_aRelatedTo as $aRelInfo) + { + $aCondReferred[] = $this->DescribeConditionRelTo($aRelInfo); + } + if (count($aCondReferred) > 0) + { + $aConditions[] = implode(" and ", $aCondReferred); + } + + return implode(" and ", $aConditions); + } + + public function __DescribeHTML() + { + $sConditionDesc = $this->DescribeConditions(); + if (!empty($sConditionDesc)) + { + return "Objects of class '$this->m_sClass', $sConditionDesc"; + } + return "Any object of class '$this->m_sClass'"; + } + + protected function TransferConditionExpression($oFilter, $aTranslation) + { + $oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false); + $this->AddConditionExpression($oTranslated); + } + + public function ResetCondition() + { + $this->m_oSearchCondition = new TrueExpression(); + // ? is that enough, do I need to rebuild the list after the subqueries ? + $this->m_aClasses = array($this->m_sClassAlias => $this->m_sClass); + } + + public function AddConditionExpression($oExpression) + { + $this->m_oSearchCondition = $this->m_oSearchCondition->LogAnd($oExpression); + } + + public function AddCondition($sFilterCode, $value, $sOpCode = null) + { + MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->m_sClass)); + $oFilterDef = MetaModel::GetClassFilterDef($this->m_sClass, $sFilterCode); + + if (empty($sOpCode)) + { + $sOpCode = $oFilterDef->GetLooseOperator(); + } + MyHelpers::CheckKeyInArray('operator', $sOpCode, $oFilterDef->GetOperators()); + + // Preserve backward compatibility - quick n'dirty way to change that API semantic + // + $oField = new FieldExpression($sFilterCode, $this->m_sClassAlias); + switch($sOpCode) + { + case 'SameDay': + case 'SameMonth': + case 'SameYear': + case 'Today': + case '>|': + case '<|': + case '=|': + throw new CoreException('Deprecated operator, please consider using OQL (SQL) expressions like "(TO_DAYS(NOW()) - TO_DAYS(x)) AS AgeDays"', array('operator' => $sOpCode)); + break; + + case "IN": + $sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')'; + $sOQLCondition = $oField->Render()." IN $sListExpr"; + break; + + case "NOTIN": + $sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')'; + $sOQLCondition = $oField->Render()." NOT IN $sListExpr"; + break; + + case 'Contains': + $oRightExpr = new ScalarExpression("%$value%"); + $sOperator = 'LIKE'; + break; + + case 'Begins with': + $oRightExpr = new ScalarExpression("$value%"); + $sOperator = 'LIKE'; + break; + + case 'Finishes with': + $oRightExpr = new ScalarExpression("%$value"); + $sOperator = 'LIKE'; + break; + + default: + $oRightExpr = new ScalarExpression($value); + $sOperator = $sOpCode; + } + + switch($sOpCode) + { + case "IN": + case "NOTIN": + $oNewCondition = Expression::FromOQL($sOQLCondition); + break; + + case 'Contains': + case 'Begins with': + case 'Finishes with': + default: + $oNewCondition = new BinaryExpression($oField, $sOperator, $oRightExpr); + } + + $this->AddConditionExpression($oNewCondition); + } + + public function AddCondition_FullText($sFullText) + { + $this->m_aFullText[] = $sFullText; + } + + protected function AddToNameSpace(&$aClassAliases, &$aAliasTranslation) + { + $sOrigAlias = $this->m_sClassAlias; + if (array_key_exists($sOrigAlias, $aClassAliases)) + { + $this->m_sClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $oFilter->GetClass()); + // Translate the condition expression with the new alias + $aAliasTranslation[$sOrigAlias]['*'] = $this->m_sClassAlias; + } + + foreach($this->m_aPointingTo as $sExtKeyAttCode=>$oFilter) + { + $oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation); + } + + foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences) + { + foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter) + { + $oForeignFilter->AddToNameSpace($aClassAliases, $aAliasTranslation); + } + } + } + + public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode) + { + $aAliasTranslation = array(); + $res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation); + $this->TransferConditionExpression($oFilter, $aAliasTranslation); + return $res; + } + + protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation) + { + if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode)) + { + trigger_error("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored", E_USER_WARNING); + } + $oAttExtKey = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode); + if(!MetaModel::IsSameFamilyBranch($oFilter->GetClass(), $oAttExtKey->GetTargetClass())) + { + trigger_error("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}", E_USER_ERROR); + } + + if (array_key_exists($sExtKeyAttCode, $this->m_aPointingTo)) + { + $this->m_aPointingTo[$sExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation); + } + else + { + $sOrigAlias = $oFilter->GetClassAlias(); + $sKeyClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $oFilter->GetClass()); + if ($sKeyClassAlias != $sOrigAlias) + { + // Translate the condition expression with the new alias + $aAliasTranslation[$sOrigAlias]['*'] = $sKeyClassAlias; + } + + // #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!! + $oNewFilter = clone $oFilter; + $oNewFilter->ResetCondition(); + + $this->m_aPointingTo[$sExtKeyAttCode] = $oNewFilter; + } + } + + public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode) + { + $aAliasTranslation = array(); + $res = $this->AddCondition_ReferencedBy_InNameSpace($oFilter, $sForeignExtKeyAttCode, $this->m_aClasses, $aAliasTranslation); + $this->TransferConditionExpression($oFilter, $aAliasTranslation); + return $res; + } + + public function AddCondition_ReferencedBy_InNameSpace(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, &$aClassAliases, &$aAliasTranslation) + { + $sForeignClass = $oFilter->GetClass(); + $sForeignClassAlias = $oFilter->GetClassAlias(); + if (!MetaModel::IsValidKeyAttCode($sForeignClass, $sForeignExtKeyAttCode)) + { + trigger_error("The attribute code '$sForeignExtKeyAttCode' is not an external key of the class '{$sForeignClass}' - the condition will be ignored", E_USER_WARNING); + } + $oAttExtKey = MetaModel::GetAttributeDef($sForeignClass, $sForeignExtKeyAttCode); + if(!MetaModel::IsSameFamilyBranch($this->GetClass(), $oAttExtKey->GetTargetClass())) + { + trigger_error("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::$sForeignExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}", E_USER_ERROR); + } + if (array_key_exists($sForeignClass, $this->m_aReferencedBy) && array_key_exists($sForeignExtKeyAttCode, $this->m_aReferencedBy[$sForeignClass])) + { + $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation); + } + else + { + $sOrigAlias = $oFilter->GetClassAlias(); + $sKeyClassAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $oFilter->GetClass()); + if ($sKeyClassAlias != $sOrigAlias) + { + // Translate the condition expression with the new alias + $aAliasTranslation[$sOrigAlias]['*'] = $sKeyClassAlias; + } + + // #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!! + $oNewFilter = clone $oFilter; + $oNewFilter->ResetCondition(); + + $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]= $oNewFilter; + } + } + + public function AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget) + { + $oLinkFilterFinal = clone $oLinkFilter; + $oLinkFilterFinal->AddCondition_PointingTo($sExtKeyAttCodeToMe); + + $this->AddCondition_ReferencedBy($oLinkFilterFinal, $sExtKeyAttCodeToMe); + } + + public function AddCondition_RelatedTo(DBObjectSearch $oFilter, $sRelCode, $iMaxDepth) + { + MyHelpers::CheckValueInArray('relation code', $sRelCode, MetaModel::EnumRelations()); + $this->m_aRelatedTo[] = array('flt'=>$oFilter, 'relcode'=>$sRelCode, 'maxdepth'=>$iMaxDepth); + } + + public function MergeWith($oFilter) + { + $aAliasTranslation = array(); + $res = $this->MergeWith_InNamespace($oFilter, $this->m_aClasses, $aAliasTranslation); + $this->TransferConditionExpression($oFilter, $aAliasTranslation); + return $res; + } + + protected function MergeWith_InNamespace($oFilter, &$aClassAliases, &$aAliasTranslation) + { + if ($this->GetClass() != $oFilter->GetClass()) + { + trigger_error("Attempting to merge a filter of class '{$this->GetClass()}' with a filter of class '{$oFilter->GetClass()}'", E_USER_ERROR); + } + + // Translate search condition into our aliasing scheme + $aAliasTranslation[$oFilter->GetClassAlias()]['*'] = $this->GetClassAlias(); + + $this->m_aFullText = array_merge($this->m_aFullText, $oFilter->m_aFullText); + $this->m_aRelatedTo = array_merge($this->m_aRelatedTo, $oFilter->m_aRelatedTo); + + foreach($oFilter->m_aPointingTo as $sExtKeyAttCode=>$oExtFilter) + { + $this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation); + } + foreach($oFilter->m_aReferencedBy as $sForeignClass => $aReferences) + { + foreach($aReferences as $sForeignExtKeyAttCode => $oForeignFilter) + { + $this->AddCondition_ReferencedBy_InNamespace($oForeignFilter, $sForeignExtKeyAttCode, $aClassAliases, $aAliasTranslation); + } + } + } + + + public function GetClassName($sAlias) {return $this->m_aClasses[$sAlias];} + public function GetClasses() {return $this->m_aClasses;} + + public function GetClass() {return $this->m_sClass;} + public function GetClassAlias() {return $this->m_sClassAlias;} + public function GetCriteria() {return $this->m_oSearchCondition;} + public function GetCriteria_FullText() {return $this->m_aFullText;} + public function GetCriteria_PointingTo($sKeyAttCode = "") + { + if (empty($sKeyAttCode)) + { + return $this->m_aPointingTo; + } + if (!array_key_exists($sKeyAttCode, $this->m_aPointingTo)) return null; + return $this->m_aPointingTo[$sKeyAttCode]; + } + public function GetCriteria_ReferencedBy($sRemoteClass = "", $sForeignExtKeyAttCode = "") + { + if (empty($sRemoteClass)) + { + return $this->m_aReferencedBy; + } + if (!array_key_exists($sRemoteClass, $this->m_aReferencedBy)) return null; + if (empty($sForeignExtKeyAttCode)) + { + return $this->m_aReferencedBy[$sRemoteClass]; + } + if (!array_key_exists($sForeignExtKeyAttCode, $this->m_aReferencedBy[$sRemoteClass])) return null; + return $this->m_aReferencedBy[$sRemoteClass][$sForeignExtKeyAttCode]; + } + public function GetCriteria_RelatedTo() + { + return $this->m_aRelatedTo; + } + + public function RenderCondition() + { + return $this->m_oSearchCondition->Render(); + } + + public function serialize() + { + // Efficient but resulting in long strings: + // -> return (base64_encode(serialize($this))); + + $sValue = $this->GetClass()."\n"; + $sValue .= $this->GetClassAlias()."\n"; + + foreach($this->m_aClasses as $sClassAlias => $sClass) + { + // A stands for "Aliases" + $sValue .= "A:$sClassAlias:$sClass\n"; + } + foreach($this->m_aFullText as $sFullText) + { + // F stands for "Full text" + $sValue .= "F:".$sFullText."\n"; + } + $sValue .= "C:".$this->m_oSearchCondition->serialize()."\n"; + + foreach($this->m_aPointingTo as $sExtKey=>$oFilter) + { + // P stands for "Pointing to" + $sValue .= "P:".$sExtKey.":".$oFilter->serialize()."\n"; + } + foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences) + { + foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter) + { + // R stands for "Referenced by" + $sValue .= "R:".$sForeignExtKeyAttCode.":".$oForeignFilter->serialize()."\n"; + } + } + foreach($this->m_aRelatedTo as $aRelatedTo) + { + $oFilter = $aRelatedTo['flt']; + $sRelCode = $aRelatedTo['relcode']; + $iMaxDepth = $aRelatedTo['maxdepth']; + + $sValue .= "T:".$oFilter->serialize().":$sRelCode:$iMaxDepth"; + } + return base64_encode($sValue); + } + + static public function unserialize($sValue) + { + // See comment above... + // -> return (unserialize(base64_decode($sValue))); + + $sClearText = base64_decode($sValue); + $aValues = split("\n", $sClearText); + $i = 0; + $sClass = $aValues[$i++]; + $sClassAlias = $aValues[$i++]; + $oFilter = new DBObjectSearch($sClass, $sClassAlias); + while($i < count($aValues) && !empty($aValues[$i])) + { + $aCondition = split(":", $aValues[$i++]); + switch ($aCondition[0]) + { + case "A": + $oFilter->m_aClasses[$aCondition[1]] = $aCondition[2]; + break; + case "F": + $oFilter->AddCondition_FullText($aCondition[1]); + break; + case "C": + $oFilter->m_oSearchCondition = Expression::unserialize($aCondition[1]); + break; + case "P": + //$oAtt = DBObject::GetAttributeDef($sClass, $aCondition[1]); + //$sRemoteClass = $oAtt->GetTargetClass(); + $oSubFilter = self::unserialize($aCondition[2]); + $sExtKeyAttCode = $aCondition[1]; + $oFilter->AddCondition_PointingTo($oSubFilter, $sExtKeyAttCode); + break; + case "R": + $oRemoteFilter = self::unserialize($aCondition[2]); + $sExtKeyAttCodeToMe = $aCondition[1]; + $oFilter->AddCondition_ReferencedBy($oRemoteFilter, $sExtKeyAttCodeToMe); + break; + case "T": + $oSubFilter = self::unserialize($aCondition[1]); + $sRelCode = $aCondition[2]; + $iMaxDepth = $aCondition[3]; + $oFilter->AddCondition_RelatedTo($oSubFilter, $sRelCode, $iMaxDepth); + default: + trigger_error("invalid filter definition (cannot unserialize the data, clear text = '$sClearText')", E_USER_ERROR); + } + } + return $oFilter; + } + + // SImple BUt Structured Query Languag - SubuSQL + // + static private function Value2Expression($value) + { + $sRet = $value; + if (is_array($value)) + { + $sRet = VS_START.implode(', ', $value).VS_END; + } + else if (!is_numeric($value)) + { + $sRet = "'".addslashes($value)."'"; + } + return $sRet; + } + static private function Expression2Value($sExpr) + { + $retValue = $sExpr; + if ((substr($sExpr, 0, 1) == "'") && (substr($sExpr, -1, 1) == "'")) + { + $sNoQuotes = substr($sExpr, 1, -1); + return stripslashes($sNoQuotes); + } + if ((substr($sExpr, 0, 1) == VS_START) && (substr($sExpr, -1, 1) == VS_END)) + { + $sNoBracket = substr($sExpr, 1, -1); + $aRetValue = array(); + foreach (explode(",", $sNoBracket) as $sItem) + { + $aRetValue[] = self::Expression2Value(trim($sItem)); + } + return $aRetValue; + } + return $retValue; + } + + public function ToSibusQL() + { + $aConds = array(); // string conditions, to be merged into a logical AND + foreach($this->m_aFullText as $sFullText) + { + $aConds[] = "* HAS ".self::Value2Expression($sFullText); + } + // #@# todo - changer ToSibusQL en ToOQL et l'implementer ! + // $aConds[] = $this->m_oSearchCondition->ToSibusQL + /* + foreach($this->m_aCriteria as $aCritInfo) + { + $aConds[] = $aCritInfo["filtercode"]." ".$aCritInfo["opcode"]." ".self::Value2Expression($aCritInfo["value"]); + } + */ + foreach($this->m_aPointingTo as $sExtKey=>$oFilter) + { + $aConds[] = $sExtKey." IN (".$oFilter->ToSibusQL().")"; + } + foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences) + { + foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter) + { + $aConds[] = "PKEY IS ".$sForeignExtKeyAttCode." IN (".$oForeignFilter->ToSibusQL().")"; + } + } + foreach($this->m_aRelatedTo as $aRelatedTo) + { + $oFilter = $aRelatedTo['flt']; + $sRelCode = $aRelatedTo['relcode']; + $iMaxDepth = $aRelatedTo['maxdepth']; + + $aConds[] = "RELATED ($sRelCode, $iMaxDepth) TO (".$oFilter->ToSibuSQL().")"; + } + + $sValue = $this->GetClass(); + if (count($aConds) > 0) + { + $sValue .= ": ".implode(" AND ", $aConds); + } + return $sValue; + } + + static private function privProcessParams($sQuery, array $aParams, $oDbObject) + { + $iPlaceHoldersCount = preg_match_all(SIBUSQLPARAMREGEXP, $sQuery, $aMatches, PREG_SET_ORDER); + if ($iPlaceHoldersCount > 0) + { + foreach($aMatches as $aMatch) + { + $sStringToSearch = $aMatch[0]; + $sParameterName = $aMatch[1]; + $sDefaultValue = $aMatch[2]; + $sDescription = $aMatch[3]; + + $sValue = $sDefaultValue; + if (array_key_exists($sParameterName, $aParams)) + { + $sValue = $aParams[$sParameterName]; + unset($aParams[$sParameterName]); + } + else if (is_object($oDbObject)) + { + if (strpos($sParameterName, "this.") === 0) + { + $sAttCode = substr($sParameterName, strlen("this.")); + if ($sAttCode == 'pkey') + { + $sValue = $oDbObject->GetKey(); + } + else if ($sAttCode == 'class') + { + $sValue = get_class($oDbObject); + } + else if (MetaModel::IsValidAttCode(get_class($oDbObject), $sAttCode)) + { + $sValue = $oDbObject->Get($sAttCode); + } + } + } + $sQuery = str_replace($sStringToSearch, $sValue, $sQuery); + } + } + if (count($aParams) > 0) + { + trigger_error("Unused parameter(s) for this SibusQL expression: (".implode(', ', array_keys($aParams)).")"); + } + return $sQuery; + } + + static public function ListSibusQLParams($sQuery) + { + $aRet = array(); + $iPlaceHoldersCount = preg_match_all(SIBUSQLPARAMREGEXP, $sQuery, $aMatches, PREG_SET_ORDER); + if ($iPlaceHoldersCount > 0) + { + foreach($aMatches as $aMatch) + { + $sStringToSearch = $aMatch[0]; + $sParameterName = $aMatch[1]; + $sDefaultValue = $aMatch[2]; + $sDescription = $aMatch[3]; + $aRet[$sParameterName]["description"] = $sDescription; + $aRet[$sParameterName]["default"] = $sDefaultValue; + } + } + return $aRet; + } + + protected function OQLExpressionToCondition($sQuery, $oExpression, $aClassAliases) + { + if ($oExpression instanceof BinaryOqlExpression) + { + $sOperator = $oExpression->GetOperator(); + $oLeft = $this->OQLExpressionToCondition($sQuery, $oExpression->GetLeftExpr(), $aClassAliases); + $oRight = $this->OQLExpressionToCondition($sQuery, $oExpression->GetRightExpr(), $aClassAliases); + return new BinaryExpression($oLeft, $sOperator, $oRight); + } + elseif ($oExpression instanceof FieldOqlExpression) + { + $sClassAlias = $oExpression->GetParent(); + $sFltCode = $oExpression->GetName(); + if (empty($sClassAlias)) + { + $iPos = $oExpression->GetPosition(); + throw new OqlNormalizeException('Missing class specification', $sQuery, 0, $iPos, ''); + } + if (!array_key_exists($sClassAlias, $aClassAliases)) + { + $iPos = $oExpression->GetPosition(); + throw new OqlNormalizeException('Unknown class', $sQuery, 0, $iPos, $sClassAlias, array_keys($aClassAliases)); + } + $sClass = $aClassAliases[$sClassAlias]; + if (!MetaModel::IsValidFilterCode($sClass, $sFltCode)) + { + $iPos = $oExpression->GetPosition(); + throw new OqlNormalizeException('Unknown filter code', $sQuery, 0, $iPos, "$sFltCode in class $sClassAlias", MetaModel::GetFiltersList($sClass)); + } + + return new FieldExpression($sFltCode, $sClassAlias); + } + elseif ($oExpression instanceof TrueOqlExpression) + { + return new TrueExpression; + } + elseif ($oExpression instanceof ScalarOqlExpression) + { + return new ScalarExpression($oExpression->GetValue()); + } + elseif ($oExpression instanceof ListOqlExpression) + { + return new ListExpression($oExpression->GetItems()); + } + elseif ($oExpression instanceof FunctionOqlExpression) + { + return new FunctionExpression($oExpression->GetVerb(), $oExpression->GetArgs()); + } + else + { + throw new CoreException('Unknown expression type', array('class'=>get_class($oExpression), 'query'=>$sQuery)); + } + } + + static public function FromOQL($sQuery, array $aParams = array(), $oObject = null) + { + if (empty($sQuery)) return null; + + $oOql = new OqlInterpreter($sQuery); + $oOqlQuery = $oOql->ParseQuery(); + + $sClass = $oOqlQuery->GetClass(); + $sClassAlias = $oOqlQuery->GetClassAlias(); + + if (!MetaModel::IsValidClass($sClass)) + { + throw new OqlNormalizeException('Unknown class', $sQuery, 0, 0, $sClass, MetaModel::GetClasses()); + } + + $oResultFilter = new DBObjectSearch($sClass, $sClassAlias); + $oResultFilter->m_aClasses = array($sClassAlias => $sClass); + + // Maintain an array of filters, because the flat list is in fact referring to a tree + // And this will be an easy way to dispatch the conditions + // $oResultFilter will be referenced by the other filters, or the other way around... + $aJoinItems = array($sClassAlias => $oResultFilter); + + $aJoinSpecs = $oOqlQuery->GetJoins(); + if (is_array($aJoinSpecs)) + { + foreach ($aJoinSpecs as $oJoinSpec) + { + $sJoinClass = $oJoinSpec->GetClass(); + $sJoinClassAlias = $oJoinSpec->GetClassAlias(); + if (!MetaModel::IsValidClass($sJoinClass)) + { + throw new OqlNormalizeException('Unknown class', $sQuery, 0, 0, $sJoinClass, MetaModel::GetClasses()); + } + if (array_key_exists($sJoinClassAlias, $oResultFilter->m_aClasses)) + { + if ($sJoinClassAlias != $sJoinClass) + { + throw new OqlNormalizeException('Duplicate class alias', $sQuery, 0, 0, $sJoinClassAlias); + } + else + { + throw new OqlNormalizeException('Duplicate class name', $sQuery, 0, 0, $sJoinClass); + } + } + + // Assumption: ext key on the left only !!! + // normalization should take care of this + $oLeftField = $oJoinSpec->GetLeftField(); + $sFromClass = $oLeftField->GetParent(); + $sExtKeyAttCode = $oLeftField->GetName(); + + $oRightField = $oJoinSpec->GetRightField(); + $sToClass = $oRightField->GetParent(); + $sPKeyDescriptor = $oRightField->GetName(); + if ($sPKeyDescriptor != 'id') + { + throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sQuery, 0, $oRightField->GetPosition(), $sPKeyDescriptor, array('id')); + } + + $oResultFilter->m_aClasses[$sJoinClassAlias] = $sJoinClass; + $aJoinItems[$sJoinClassAlias] = new DBObjectSearch($sJoinClass, $sJoinClassAlias); + + if (!array_key_exists($sFromClass, $aJoinItems)) + { + throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sQuery, 0, $oLeftField->GetPosition(), $sFromClass, array_keys($aJoinItems)); + } + if (!array_key_exists($sToClass, $aJoinItems)) + { + throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sQuery, 0, $oRightField->GetPosition(), $sToClass, array_keys($aJoinItems)); + } + $aExtKeys = array_keys(MetaModel::GetExternalKeys($oResultFilter->m_aClasses[$sFromClass])); + if (!in_array($sExtKeyAttCode, $aExtKeys)) + { + throw new OqlNormalizeException('Unknown external key in join condition (left expression)', $sQuery, 0, $oLeftField->GetPosition(), $sExtKeyAttCode, $aExtKeys); + } + + if ($sFromClass == $sJoinClassAlias) + { + $aJoinItems[$sToClass]->AddCondition_ReferencedBy($aJoinItems[$sFromClass], $sExtKeyAttCode); + } + else + { + $aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode); + } + } + } + + $oConditionTree = $oOqlQuery->GetCondition(); + if ($oConditionTree instanceof Expression) + { + $oResultFilter->m_oSearchCondition = $oResultFilter->OQLExpressionToCondition($sQuery, $oConditionTree, $oResultFilter->m_aClasses); + } + + return $oResultFilter; + } + + static public function FromSibusQL($sQuery, array $aParams = array(), $oObject = null) + { + if (empty($sQuery)) return null; + $sQuery = self::privProcessParams($sQuery, $aParams, $oObject); + + $iSepPos = strpos($sQuery, ":"); + if ($iSepPos === false) + { + if (preg_match('@^\\s*SELECT@', $sQuery)) + { + return self::FromOQL($sQuery, $aParams, $oObject); + } + // Only the class was specified -> all rows are required + $sClass = trim($sQuery); + $oFilter = new DBObjectSearch($sClass); + } + else + { + $sClass = trim(substr($sQuery, 0, $iSepPos)); + $sConds = trim(substr($sQuery, $iSepPos + 1)); + $aValues = split(" AND ", $sConds); + + $oFilter = new DBObjectSearch($sClass); + + foreach ($aValues as $sCond) + { + $sCond = trim($sCond); + + if (strpos($sCond, "* HAS ") === 0) + { + $sValue = self::Expression2Value(substr($sCond, strlen("* HAS "))); + $oFilter->AddCondition_FullText($sValue); + } + else if (preg_match("@^(\S+) IN \\((.+)\\)$@", $sCond, $aMatches)) + { + $sExtKeyAttCode = $aMatches[1]; + $sFilterExp = $aMatches[2]; + + $oSubFilter = self::FromSibuSQL($sFilterExp); + $oFilter->AddCondition_PointingTo($oSubFilter, $sExtKeyAttCode); + } + else if (strpos($sCond, "PKEY IS ") === 0) + { + if (preg_match("@^PKEY IS (\S+) IN \\((.+)\\)$@", $sCond, $aMatches)) + { + $sExtKeyAttCodeToMe = $aMatches[1]; + $sFilterExp = $aMatches[2]; + $oRemoteFilter = self::FromSibuSQL($sFilterExp); + $oFilter->AddCondition_ReferencedBy($oRemoteFilter, $sExtKeyAttCodeToMe); + } + } + else if (strpos($sCond, "RELATED") === 0) + { + if (preg_match("@^RELATED\s*\\((.+)\\)\s*TO\s*\\((.+)\\)@", trim($sCond), $aMatches)) + { + $aRelation = explode(',', trim($aMatches[1])); + $sRelCode = trim($aRelation[0]); + $iMaxDepth = intval(trim($aRelation[1])); + $sFilterExp = trim($aMatches[2]); + + $oSubFilter = self::FromSibuSQL($sFilterExp); + $oFilter->AddCondition_RelatedTo($oSubFilter, $sRelCode, $iMaxDepth); + } + } + else + { + $sOperandExpr = "'.*'|\d+|-\d+|".VS_START.".+".VS_END; + if (preg_match("@^(\S+)\s+(.*)\s+($sOperandExpr)$@", $sCond, $aMatches)) + { + $sFltCode = trim($aMatches[1]); + $sOpCode = trim($aMatches[2]); + $value = self::Expression2Value($aMatches[3]); + $oFilter->AddCondition($sFltCode, $value, $sOpCode); + } + else + { + trigger_error("Wrong format for filter definition: '$sQuery'"); + } + } + } + } + return $oFilter; + } + + // Sexy display of a SibuSQL expression + static public function SibuSQLAsHtml($sQuery) + { + $sQuery = htmlentities($sQuery); + $aParams = self::ListSibusQLParams($sQuery); + $aParamValues = array(); + foreach ($aParams as $sParamName => $aParamInfo) + { + $sDescription = $aParamInfo["description"]; + $sDefaultValue = $aParamInfo["default"]; + $aParamValues[$sParamName] = "$sParamName"; + } + $sQuery = self::privProcessParams($sQuery, $aParamValues, null); + return $sQuery; + } + + public function toxpath() + { + // #@# a voir... + } + static public function fromxpath() + { + // #@# a voir... + } +} + + +?> diff --git a/core/dbobjectset.class.php b/core/dbobjectset.class.php new file mode 100644 index 000000000..4ab3761a9 --- /dev/null +++ b/core/dbobjectset.class.php @@ -0,0 +1,255 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +class DBObjectSet +{ + private $m_oFilter; + private $m_aOrderBy; + public $m_bLoaded; + private $m_aData; + private $m_aId2Row; + private $m_iCurrRow; + + public function __construct($oFilter, $aOrderBy = array()) + { + $this->m_oFilter = $oFilter; + $this->m_aOrderBy = $aOrderBy; + + $this->m_bLoaded = false; + $this->m_aData = array(); + $this->m_aId2Row = array(); + $this->m_iCurrRow = 0; + } + + public function __destruct() + { + } + + public function __toString() + { + $sRet = ''; + $this->Rewind(); + $sRet .= "Set (".$this->m_oFilter->ToSibuSQL().")
\n"; + $sRet .= "Query:
".MetaModel::MakeSelectQuery($this->m_oFilter, array()).")
\n"; + + $sRet .= $this->Count()." records
\n"; + if ($this->Count() > 0) + { + $sRet .= "
    \n"; + while ($oObj = $this->Fetch()) + { + $sRet .= "
  • ".$oObj->__toString()."
  • \n"; + } + $sRet .= "
\n"; + } + return $sRet; + } + + static public function FromScratch($sClass) + { + $oFilter = new CMDBSearchFilter($sClass); + $oRetSet = new self($oFilter); + $oRetSet->m_bLoaded = true; // no DB load + return $oRetSet; + } + + static public function FromArray($sClass, $aObjects) + { + $oFilter = new CMDBSearchFilter($sClass); + $oRetSet = new self($oFilter); + $oRetSet->m_bLoaded = true; // no DB load + $oRetSet->AddObjectArray($aObjects); + return $oRetSet; + } + + public function ToArray($bWithId = true) + { + $aRet = array(); + $this->Rewind(); + while ($oObject = $this->Fetch()) + { + if ($bWithId) + { + $aRet[$oObject->GetKey()] = $oObject; + } + else + { + $aRet[] = $oObject; + } + } + return $aRet; + } + + public function GetFilter() + { + return $this->m_oFilter; + } + + public function GetClass() + { + return $this->m_oFilter->GetClass(); + } + + public function GetRootClass() + { + return MetaModel::GetRootClass($this->GetClass()); + } + + public function Load() + { + if ($this->m_bLoaded) return; +// #@# debug - echo "Loading (".$this->m_oFilter->ToSibuSQL().")....
\n"; + $sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy); + $resQuery = CMDBSource::Query($sSQL); + if (!$resQuery) return; + + while ($aRow = CMDBSource::FetchArray($resQuery)) + { + $sClass = $this->m_oFilter->GetClass(); + $oObject = MetaModel::GetObjectByRow($sClass, $aRow); + $this->AddObject($oObject); + } + CMDBSource::FreeResult($resQuery); + + $this->m_bLoaded = true; + } + + public function Count() + { + if (!$this->m_bLoaded) $this->Load(); + return count($this->m_aData); + } + + public function Fetch() + { + if (!$this->m_bLoaded) $this->Load(); + + if ($this->m_iCurrRow >= count($this->m_aData)) + { + return null; + } + $oRetObj = $this->m_aData[$this->m_iCurrRow]; + $this->m_iCurrRow++; + return $oRetObj; + } + + public function Rewind() + { + $this->Seek(0); + } + + public function Seek($iRow) + { + if (!$this->m_bLoaded) $this->Load(); + + $this->m_iCurrRow = min($iRow, count($this->m_aData)); + return $this->m_iCurrRow; + } + + public function AddObject($oObject) + { + // ?usefull? if ($oObject->GetClass() != $this->GetClass()) return; + + // it is mandatory to avoid duplicates + if (array_key_exists($oObject->GetKey(), $this->m_aId2Row)) return; + + // Do not load here, because the load uses that method too + $iNextPos = count($this->m_aData); + $this->m_aData[$iNextPos] = $oObject; + $this->m_aId2Row[$oObject->GetKey()] = $iNextPos; + } + + public function RemoveObject($iRow) + { + trigger_error("#@# not implemented! ca sert a quoi ?"); + } + + public function AddObjectArray($aObjects) + { + foreach ($aObjects as $oObj) + { + $this->AddObject($oObj); + } + } + + public function Merge($oObjectSet) + { + if ($this->GetRootClass() != $oObjectSet->GetRootClass()) + { + trigger_error("Could not merge two objects sets if they don't have the same root class"); + } + if (!$this->m_bLoaded) $this->Load(); + + $oObjectSet->Seek(0); + while ($oObject = $oObjectSet->Fetch()) + { + $this->AddObject($oObject); + } + } + + public function CreateIntersect($oObjectSet) + { + if ($this->GetRootClass() != $oObjectSet->GetRootClass()) + { + trigger_error("Could not 'intersect' two objects sets if they don't have the same root class"); + } + if (!$this->m_bLoaded) $this->Load(); + + $oNewSet = DBObjectSet::FromScratch($this->GetClass()); + + $oObjectSet->Seek(0); + while ($oObject = $oObjectSet->Fetch()) + { + if (array_key_exists($oObject->GetKey(), $this->m_aId2Row)) + { + $oNewSet->AddObject($oObject); + } + } + return $oNewSet; + } + + public function CreateDelta($oObjectSet) + { + if ($this->GetRootClass() != $oObjectSet->GetRootClass()) + { + trigger_error("Could not 'delta' two objects sets if they don't have the same root class"); + } + if (!$this->m_bLoaded) $this->Load(); + + $oNewSet = DBObjectSet::FromScratch($this->GetClass()); + + $oObjectSet->Seek(0); + while ($oObject = $oObjectSet->Fetch()) + { + if (!array_key_exists($oObject->GetKey(), $this->m_aId2Row)) + { + $oNewSet->AddObject($oObject); + } + } + return $oNewSet; + } + + public function GetRelatedObjects($sRelCode, $iMaxDepth = 99) + { + $aVisited = array(); // optimization for consecutive calls of MetaModel::GetRelatedObjects + $this->Seek(0); + while ($oObject = $this->Fetch()) + { + $aRelatedObjs = $oObject->GetRelatedObjects($sRelCode, $iMaxDepth, $aVisited); + } + return $aRelatedObjs; + } +} + +?> diff --git a/core/expression.class.inc.php b/core/expression.class.inc.php new file mode 100644 index 000000000..427fcb4ad --- /dev/null +++ b/core/expression.class.inc.php @@ -0,0 +1,431 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +abstract class Expression +{ + // recursive translation of identifiers + abstract public function Translate($aTranslationData, $bMatchAll = true); + + // recursive rendering + abstract public function Render(); + + // recursively builds an array of class => fieldname + abstract public function ListRequiredFields(); + + public function RequiresField($sClass, $sFieldName) + { + // #@# todo - optimize : this is called quite often when building a single query ! + $aRequired = $this->ListRequiredFields(); + if (!in_array($sClass.'.'.$sFieldName, $aRequired)) return false; + return true; + } + + public function serialize() + { + return base64_encode($this->Render()); + } + + static public function unserialize($sValue) + { + return self::FromOQL(base64_decode($sValue)); + } + + static public function FromOQL($sConditionExpr) + { + $oOql = new OqlInterpreter($sConditionExpr); + $oExpression = $oOql->ParseExpression(); + + return $oExpression; + } + + public function LogAnd($oExpr) + { + return new BinaryExpression($this, 'AND', $oExpr); + } + + public function LogOr($oExpr) + { + return new BinaryExpression($this, 'OR', $oExpr); + } + +} + + +class BinaryExpression extends Expression +{ + protected $m_oLeftExpr; // filter code or an SQL expression (later?) + protected $m_oRightExpr; + protected $m_sOperator; + + public function __construct($oLeftExpr, $sOperator, $oRightExpr) + { + if (!is_object($oLeftExpr)) + { + throw new CoreException('Expecting an Expression object on the left hand', array('found_type' => gettype($oLeftExpr))); + } + if (!is_object($oRightExpr)) + { + throw new CoreException('Expecting an Expression object on the right hand', array('found_type' => gettype($oRightExpr))); + } + if (!$oLeftExpr instanceof Expression) + { + throw new CoreException('Expecting an Expression object on the left hand', array('found_class' => get_class($oLeftExpr))); + } + if (!$oRightExpr instanceof Expression) + { + throw new CoreException('Expecting an Expression object on the right hand', array('found_class' => get_class($oRightExpr))); + } + $this->m_oLeftExpr = $oLeftExpr; + $this->m_oRightExpr = $oRightExpr; + $this->m_sOperator = $sOperator; + } + + public function GetLeftExpr() + { + return $this->m_oLeftExpr; + } + + public function GetRightExpr() + { + return $this->m_oRightExpr; + } + + public function GetOperator() + { + return $this->m_sOperator; + } + + // recursive rendering + public function Render() + { + $sOperator = $this->GetOperator(); + $sLeft = $this->GetLeftExpr()->Render(); + $sRight = $this->GetRightExpr()->Render(); + return "($sLeft $sOperator $sRight)"; + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + $oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll); + $oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll); + return new BinaryExpression($oLeft, $this->GetOperator(), $oRight); + } + + public function ListRequiredFields() + { + $aLeft = $this->GetLeftExpr()->ListRequiredFields(); + $aRight = $this->GetRightExpr()->ListRequiredFields(); + return array_merge($aLeft, $aRight); + } +} + + +class UnaryExpression extends Expression +{ + protected $m_value; + + public function __construct($value) + { + $this->m_value = $value; + } + + public function GetValue() + { + return $this->m_value; + } + + // recursive rendering + public function Render() + { + return CMDBSource::Quote($this->m_value); + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + return clone $this; + } + + public function ListRequiredFields() + { + return array(); + } +} + +class ScalarExpression extends UnaryExpression +{ + public function __construct($value) + { + if (!is_scalar($value)) + { + throw new CoreException('Attempt to create a scalar expression from a non scalar', array('var_type'=>gettype($value))); + } + parent::__construct($value); + } +} + +class TrueExpression extends ScalarExpression +{ + public function __construct() + { + parent::__construct(1); + } +} + +class FieldExpression extends UnaryExpression +{ + protected $m_sParent; + protected $m_sName; + + public function __construct($sName, $sParent = '') + { + parent::__construct("$sParent.$sName"); + + $this->m_sParent = $sParent; + $this->m_sName = $sName; + } + + public function GetParent() {return $this->m_sParent;} + public function GetName() {return $this->m_sName;} + + // recursive rendering + public function Render() + { + if (empty($this->m_sParent)) + { + return "`{$this->m_sName}`"; + } + return "`{$this->m_sParent}`.`{$this->m_sName}`"; + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + if (!array_key_exists($this->m_sParent, $aTranslationData)) + { + if ($bMatchAll) throw new CoreException('Unknown parent id in translation table', array('parent_id' => $this->m_sParent, 'translation_table' => array_keys($aTranslationData))); + return clone $this; + } + if (!array_key_exists($this->m_sName, $aTranslationData[$this->m_sParent])) + { + if (!array_key_exists('*', $aTranslationData[$this->m_sParent])) + { + // #@# debug - if ($bMatchAll) MyHelpers::var_dump_html($aTranslationData, true); + if ($bMatchAll) throw new CoreException('Unknown name in translation table', array('name' => $this->m_sName, 'parent_id' => $this->m_sParent, 'translation_table' => array_keys($aTranslationData[$this->m_sParent]))); + return clone $this; + } + $sNewParent = $aTranslationData[$this->m_sParent]['*']; + $sNewName = $this->m_sName; + } + else + { + $sNewParent = $aTranslationData[$this->m_sParent][$this->m_sName][0]; + $sNewName = $aTranslationData[$this->m_sParent][$this->m_sName][1]; + } + return new FieldExpression($sNewName, $sNewParent); + } + + public function ListRequiredFields() + { + return array($this->m_sParent.'.'.$this->m_sName); + } +} + + +// Temporary, until we implement functions and expression casting! +// ... or until we implement a real full text search based in the MATCH() expression +class ListExpression extends Expression +{ + protected $m_aExpressions; + + public function __construct($aExpressions) + { + $this->m_aExpressions = $aExpressions; + } + + public function GetItems() + { + return $this->m_aExpressions; + } + + // recursive rendering + public function Render() + { + $aRes = array(); + foreach ($this->m_aExpressions as $oExpr) + { + $aRes[] = $oExpr->Render(); + } + return '('.implode(', ', $aRes).')'; + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + $aRes = array(); + foreach ($this->m_aExpressions as $oExpr) + { + $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll); + } + return new ListExpression($aRes); + } + + public function ListRequiredFields() + { + $aRes = array(); + foreach ($this->m_aExpressions as $oExpr) + { + $aRes = array_merge($aRes, $oExpr->ListRequiredFields()); + } + return $aRes; + } +} + + +class FunctionExpression extends Expression +{ + protected $m_sVerb; + protected $m_aArgs; // array of expressions + + public function __construct($sVerb, $aArgExpressions) + { + $this->m_sVerb = $sVerb; + $this->m_aArgs = $aArgExpressions; + } + + public function GetVerb() + { + return $this->m_sVerb; + } + + public function GetArgs() + { + return $this->m_aArgs; + } + + // recursive rendering + public function Render() + { + $aRes = array(); + foreach ($this->m_aArgs as $oExpr) + { + $aRes[] = $oExpr->Render(); + } + return $this->m_sVerb.'('.implode(', ', $aRes).')'; + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + $aRes = array(); + foreach ($this->m_aArgs as $oExpr) + { + $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll); + } + return new FunctionExpression($this->m_sVerb, $aRes); + } + + public function ListRequiredFields() + { + $aRes = array(); + foreach ($this->m_aArgs as $oExpr) + { + $aRes = array_merge($aRes, $oExpr->ListRequiredFields()); + } + return $aRes; + } +} + +class IntervalExpression extends Expression +{ + protected $m_oValue; // expression + protected $m_sUnit; + + public function __construct($oValue, $sUnit) + { + $this->m_oValue = $oValue; + $this->m_sUnit = $sUnit; + } + + public function GetValue() + { + return $this->m_oValue; + } + + public function GetUnit() + { + return $this->m_sUnit; + } + + // recursive rendering + public function Render() + { + return 'INTERVAL '.$this->m_oValue->Render().' '.$this->m_sUnit; + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + return new IntervalExpression($this->m_oValue->Translate($aTranslationData, $bMatchAll), $this->m_sUnit); + } + + public function ListRequiredFields() + { + return array(); + } +} + +class CharConcatExpression extends Expression +{ + protected $m_aExpressions; + + public function __construct($aExpressions) + { + $this->m_aExpressions = $aExpressions; + } + + public function GetItems() + { + return $this->m_aExpressions; + } + + // recursive rendering + public function Render() + { + $aRes = array(); + foreach ($this->m_aExpressions as $oExpr) + { + $sCol = $oExpr->Render(); + // Concat will be globally NULL if one single argument is null ! + $aRes[] = "COALESCE($sCol, '')"; + } + return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)"; + } + + public function Translate($aTranslationData, $bMatchAll = true) + { + $aRes = array(); + foreach ($this->m_aExpressions as $oExpr) + { + $aRes[] = $oExpr->Translate($aTranslationData, $bMatchAll); + } + return new CharConcatExpression($aRes); + } + + public function ListRequiredFields() + { + $aRes = array(); + foreach ($this->m_aExpressions as $oExpr) + { + $aRes = array_merge($aRes, $oExpr->ListRequiredFields()); + } + return $aRes; + } +} + +?> diff --git a/core/filterdef.class.inc.php b/core/filterdef.class.inc.php new file mode 100644 index 000000000..46ec424ed --- /dev/null +++ b/core/filterdef.class.inc.php @@ -0,0 +1,296 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +abstract class FilterDefinition +{ + abstract public function GetType(); + abstract public function GetTypeDesc(); + + protected $m_sCode; + private $m_aParams = array(); + protected function Get($sParamName) {return $this->m_aParams[$sParamName];} + + public function __construct($sCode, $aParams = array()) + { + $this->m_sCode = $sCode; + $this->m_aParams = $aParams; + $this->ConsistencyCheck(); + } + + public function OverloadParams($aParams) + { + foreach ($aParams as $sParam => $value) + { + if (!array_key_exists($sParam, $this->m_aParams)) + { + trigger_error("Unknown attribute definition parameter '$sParam', please select a value in {".implode(", ", $this->m_aParams)."}"); + } + else + { + $this->m_aParams[$sParam] = $value; + } + } + } + + // to be overloaded + static protected function ListExpectedParams() + { + return array(); + } + + private function ConsistencyCheck() + { + // Check that any mandatory param has been specified + // + $aExpectedParams = $this->ListExpectedParams(); + foreach($aExpectedParams as $sParamName) + { + if (!array_key_exists($sParamName, $this->m_aParams)) + { + $aBacktrace = debug_backtrace(); + $sTargetClass = $aBacktrace[2]["class"]; + $sCodeInfo = $aBacktrace[1]["file"]." - ".$aBacktrace[1]["line"]; + trigger_error("ERROR missing parameter '$sParamName' in ".get_class($this)." declaration for class $sTargetClass ($sCodeInfo)
\n", E_USER_ERROR); + } + } + } + + public function GetCode() {return $this->m_sCode;} + abstract public function GetLabel(); + abstract public function GetValuesDef(); + + // returns an array of opcode=>oplabel (e.g. "differs from") + abstract public function GetOperators(); + // returns an opcode + abstract public function GetLooseOperator(); + abstract public function GetFilterSQLExpr($sOpCode, $value); + abstract public function TemporaryGetSQLCol(); + + // Wrapper - no need for overloading this one + public function GetOpDescription($sOpCode) + { + $aOperators = $this->GetOperators(); + if (!array_key_exists($sOpCode, $aOperators)) + { + trigger_error("Unknown operator '$sOpCode'", E_USER_ERROR); + } + + return $aOperators[$sOpCode]; + } +} + +/** + * Match against the object unique identifier + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class FilterPrivateKey extends FilterDefinition +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("pkey_field")); + } + + public function GetType() {return "PKey";} + public function GetTypeDesc() {return "Match against object identifier";} + + public function GetLabel() + { + return "Object Private Key"; + } + + public function GetValuesDef() + { + return null; + } + + public function GetOperators() + { + return array( + "="=>"equals", + "!="=>"differs from", + "IN"=>"in", + "NOTIN"=>"not in" + ); + } + public function GetLooseOperator() + { + return "IN"; + } + + public function GetFilterSQLExpr($sOpCode, $value) + { + $sFieldName = $this->Get("pkey_field"); + // #@# not obliged to quote... these are numbers !!! + $sQValue = CMDBSource::Quote($value); + switch($sOpCode) + { + case "IN": + if (!is_array($sQValue)) trigger_error("Expected an array for argument value (sOpCode='$sOpCode')"); + return "$sFieldName IN (".implode(", ", $sQValue).")"; + + case "NOTIN": + if (!is_array($sQValue)) trigger_error("Expected an array for argument value (sOpCode='$sOpCode')"); + return "$sFieldName NOT IN (".implode(", ", $sQValue).")"; + + case "!=": + return $sFieldName." != ".$sQValue; + + case "=": + default: + return $sFieldName." = ".$sQValue; + } + } + public function TemporaryGetSQLCol() + { + return $this->Get("pkey_field"); + } +} + +/** + * Match against an existing attribute (the attribute type will determine the available operators) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class FilterFromAttribute extends FilterDefinition +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("refattribute")); + } + + public function __construct($oRefAttribute, $aParam = array()) + { + // In this very specific case, the code is the one of the attribute + // (this to get a very very simple syntax upon declaration) + $aParam["refattribute"] = $oRefAttribute; + parent::__construct($oRefAttribute->GetCode(), $aParam); + } + + public function GetType() {return "Basic";} + public function GetTypeDesc() {return "Match against field contents";} + + public function __GetRefAttribute() // for checking purposes only !!! + { + return $oAttDef = $this->Get("refattribute"); + } + + public function GetLabel() + { + $oAttDef = $this->Get("refattribute"); + return $oAttDef->GetLabel(); + } + + public function GetValuesDef() + { + $oAttDef = $this->Get("refattribute"); + return $oAttDef->GetValuesDef(); + } + + public function GetOperators() + { + $oAttDef = $this->Get("refattribute"); + return $oAttDef->GetBasicFilterOperators(); + } + public function GetLooseOperator() + { + $oAttDef = $this->Get("refattribute"); + return $oAttDef->GetBasicFilterLooseOperator(); + } + + public function GetFilterSQLExpr($sOpCode, $value) + { + $oAttDef = $this->Get("refattribute"); + return $oAttDef->GetBasicFilterSQLExpr($sOpCode, $value); + } + + public function TemporaryGetSQLCol() + { + $oAttDef = $this->Get("refattribute"); + return $oAttDef->GetSQLExpr(); + } +} + +/** + * Match against a given column (experimental -to be cleaned up later) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class FilterDBValues extends FilterDefinition +{ + static protected function ListExpectedParams() + { + return array_merge(parent::ListExpectedParams(), array("dbfield")); + } + + public function GetType() {return "Values from DB";} + public function GetTypeDesc() {return "Match against the existing values in a field";} + + public function GetLabel() + { + return "enum de valeurs DB"; + } + + public function GetValuesDef() + { + return null; + } + + public function GetOperators() + { + return array( + "IN"=>"in", + ); + } + public function GetLooseOperator() + { + return "IN"; + } + + public function GetFilterSQLExpr($sOpCode, $value) + { + $sFieldName = $this->Get("dbfield"); + if (is_array($value) && !empty($value)) + { + $sValueList = "'".implode("', '", $value)."'"; + return "$sFieldName IN ($sValueList)"; + } + return "1=1"; + } + + public function TemporaryGetSQLCol() + { + return $this->Get("dbfield"); + } +} + +?> diff --git a/core/metamodel.class.php b/core/metamodel.class.php new file mode 100644 index 000000000..b6ea7fe71 --- /dev/null +++ b/core/metamodel.class.php @@ -0,0 +1,2675 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +abstract class MetaModel +{ + /////////////////////////////////////////////////////////////////////////// + // + // STATIC Members + // + /////////////////////////////////////////////////////////////////////////// + + // Purpose: workaround the following limitation = PHP5 does not allow to know the class (derived from the current one) + // from which a static function is called (__CLASS__ and self are interpreted during parsing) + private static function GetCallersPHPClass($sExpectedFunctionName = null) + { + //var_dump(debug_backtrace()); + $aBacktrace = debug_backtrace(); + // $aBacktrace[0] is where we are + // $aBacktrace[1] is the caller of GetCallersPHPClass + // $aBacktrace[1] is the info we want + if (!empty($sExpectedFunctionName)) + { + assert('$aBacktrace[2]["function"] == $sExpectedFunctionName'); + } + return $aBacktrace[2]["class"]; + } + + // Static init -why and how it works + // + // We found the following limitations: + //- it is not possible to define non scalar constants + //- it is not possible to declare a static variable as '= new myclass()' + // Then we had do propose this model, in which a derived (non abstract) + // class should implement Init(), to call InheritAttributes or AddAttribute. + + private static function _check_subclass($sClass) + { + // See also IsValidClass()... ???? #@# + // class is mandatory + // (it is not possible to guess it when called as myderived::...) + if (!array_key_exists($sClass, self::$m_aClassParams)) + { + trigger_error("Unknown class '$sClass', expected a value in {".implode(', ', array_keys(self::$m_aClassParams))."}", E_USER_ERROR); + } + } + + public static function static_var_dump() + { + var_dump(get_class_vars(__CLASS__)); + } + + private static $m_bDebugQuery = false; + private static $m_iStackDepthRef = 0; + + public static function StartDebugQuery() + { + $aBacktrace = debug_backtrace(); + self::$m_iStackDepthRef = count($aBacktrace); + self::$m_bDebugQuery = true; + } + public static function StopDebugQuery() + { + self::$m_bDebugQuery = false; + } + public static function DbgTrace($value) + { + if (!self::$m_bDebugQuery) return; + $aBacktrace = debug_backtrace(); + $iCallStackPos = count($aBacktrace) - self::$m_bDebugQuery; + $sIndent = ""; + for ($i = 0 ; $i < $iCallStackPos ; $i++) + { + $sIndent .= " .-=^=-. "; + } + $aCallers = array(); + foreach($aBacktrace as $aStackInfo) + { + $aCallers[] = $aStackInfo["function"]; + } + $sCallers = "Callstack: ".implode(', ', $aCallers); + $sFunction = "".$aBacktrace[1]["function"].""; + + if (is_string($value)) + { + echo "$sIndent$sFunction: $value
\n"; + } + else if (is_object($value)) + { + echo "$sIndent$sFunction:\n
\n";
+			print_r($value);
+			echo "
\n"; + } + else + { + echo "$sIndent$sFunction: $value
\n"; + } + } + + private static $m_sDBName = ""; + private static $m_sTablePrefix = ""; // table prefix for the current application instance (allow several applications on the same DB) + private static $m_Category2Class = array(); + private static $m_aRootClasses = array(); // array of "classname" => "rootclass" + private static $m_aParentClasses = array(); // array of ("classname" => array of "parentclass") + private static $m_aChildClasses = array(); // array of ("classname" => array of "childclass") + + private static $m_aClassParams = array(); // array of ("classname" => array of class information) + + static public function GetParentPersistentClass($sRefClass) + { + $sClass = get_parent_class($sRefClass); + if (!$sClass) return ''; + + if ($sClass == 'DBObject') return ''; // Warning: __CLASS__ is lower case in my version of PHP + + // Note: the UI/business model may implement pure PHP classes (intermediate layers) + if (array_key_exists($sClass, self::$m_aClassParams)) + { + return $sClass; + } + return self::GetParentPersistentClass($sClass); + } + + final static public function GetName($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["name"]; + } + final static public function GetCategory($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["category"]; + } + final static public function HasCategory($sClass, $sCategory) + { + self::_check_subclass($sClass); + return (strpos(self::$m_aClassParams[$sClass]["category"], $sCategory) !== false); + } + final static public function GetClassDescription($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["description"]; + } + final static public function IsAutoIncrementKey($sClass) + { + self::_check_subclass($sClass); + return (self::$m_aClassParams[$sClass]["key_type"] == "autoincrement"); + } + final static public function GetKeyLabel($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["key_label"]; + } + final static public function GetNameAttributeCode($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["name_attcode"]; + } + final static public function GetStateAttributeCode($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["state_attcode"]; + } + final static public function GetDefaultState($sClass) + { + $sDefaultState = ''; + $sStateAttrCode = self::GetStateAttributeCode($sClass); + if (!empty($sStateAttrCode)) + { + $oStateAttrDef = self::GetAttributeDef($sClass, $sStateAttrCode); + $sDefaultState = $oStateAttrDef->GetDefaultValue(); + } + return $sDefaultState; + } + final static public function GetReconcKeys($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["reconc_keys"]; + } + final static public function GetDisplayTemplate($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["display_template"]; + } + final static public function GetAttributeOrigin($sClass, $sAttCode) + { + self::_check_subclass($sClass); + return self::$m_aAttribOrigins[$sClass][$sAttCode]; + } + final static public function GetPrequisiteAttributes($sClass, $sAttCode) + { + self::_check_subclass($sClass); + $oAtt = self::GetAttributeDef($sClass, $sAttCode); + // Temporary implementation: later, we might be able to compute + // the dependencies, based on the attributes definition + // (allowed values and default values) + if ($oAtt->IsWritable()) + { + return $oAtt->GetPrerequisiteAttributes(); + } + else + { + return array(); + } + } + // #@# restore to private ? + final static public function DBGetTable($sClass, $sAttCode = null) + { + self::_check_subclass($sClass); + if (empty($sAttCode) || ($sAttCode == "pkey")) + { + $sTableRaw = self::$m_aClassParams[$sClass]["db_table"]; + if (empty($sTableRaw)) + { + // return an empty string whenever the table is undefined, meaning that there is no table associated to this 'abstract' class + return ''; + } + else + { + return self::$m_sTablePrefix.$sTableRaw; + } + } + // This attribute has been inherited (compound objects) + return self::DBGetTable(self::$m_aAttribOrigins[$sClass][$sAttCode]); + } + final static public function DBGetKey($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["db_key_field"]; + } + final static public function DBGetClassField($sClass) + { + self::_check_subclass($sClass); + return self::$m_aClassParams[$sClass]["db_finalclass_field"]; + } + final static public function HasFinalClassField($sClass) + { + self::_check_subclass($sClass); + if (!array_key_exists("db_finalclass_field", self::$m_aClassParams[$sClass])) return false; + return (self::$m_aClassParams[$sClass]["db_finalclass_field"]); + } + final static public function IsStandaloneClass($sClass) + { + self::_check_subclass($sClass); + + $sRootClass = self::GetRootClass($sClass); + return (!self::HasFinalClassField($sRootClass)); + } + final static public function IsSameFamilyBranch($sClassA, $sClassB) + { + self::_check_subclass($sClassA); + self::_check_subclass($sClassB); + if (in_array($sClassA, self::$m_aParentClasses[$sClassB])) return true; + if (in_array($sClassB, self::$m_aParentClasses[$sClassA])) return true; + if ($sClassA == $sClassB) return true; + return false; + } + final static public function IsSameFamily($sClassA, $sClassB) + { + self::_check_subclass($sClassA); + self::_check_subclass($sClassB); + return (self::GetRootClass($sClassA) == self::GetRootClass($sClassB)); + } + + // Attributes of a given class may contain attributes defined in a parent class + // - Some attributes are a copy of the definition + // - Some attributes correspond to the upper class table definition (compound objects) + // (see also filters definition) + private static $m_aAttribDefs = array(); // array of ("classname" => array of attributes) + private static $m_aAttribOrigins = array(); // array of ("classname" => array of ("attcode"=>"sourceclass")) + private static $m_aExtKeyFriends = array(); // array of ("classname" => array of ("indirect ext key attcode"=> array of ("relative ext field"))) + final static public function ListAttributeDefs($sClass) + { + self::_check_subclass($sClass); + return self::$m_aAttribDefs[$sClass]; + } + + final public static function GetAttributesList($sClass) + { + self::_check_subclass($sClass); + return array_keys(self::$m_aAttribDefs[$sClass]); + } + + final public static function GetFiltersList($sClass) + { + self::_check_subclass($sClass); + return array_keys(self::$m_aFilterDefs[$sClass]); + } + + final public static function GetKeysList($sClass) + { + self::_check_subclass($sClass); + $aExtKeys = array(); + foreach(self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) + { + if ($oAttDef->IsExternalKey()) + { + $aExtKeys[] = $sAttCode; + } + } + return $aExtKeys; + } + + final static public function IsValidKeyAttCode($sClass, $sAttCode) + { + if (!array_key_exists($sClass, self::$m_aAttribDefs)) return false; + if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) return false; + return (self::$m_aAttribDefs[$sClass][$sAttCode]->IsExternalKey()); + } + final static public function IsValidAttCode($sClass, $sAttCode) + { + if (!array_key_exists($sClass, self::$m_aAttribDefs)) return false; + return (array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])); + } + final static public function IsAttributeOrigin($sClass, $sAttCode) + { + return (self::$m_aAttribOrigins[$sClass][$sAttCode] == $sClass); + } + + final static public function IsValidFilterCode($sClass, $sFilterCode) + { + if (!array_key_exists($sClass, self::$m_aFilterDefs)) return false; + return (array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass])); + } + public static function IsValidClass($sClass) + { + return (array_key_exists($sClass, self::$m_aAttribDefs)); + } + /** + * isValidModelClass + * + * From Doctrine ! Un bon exemple d'utilisation de l'API Reflection... + * + * Checks if what is passed is a valid Doctrine_Record + * + * @param mixed $class Can be a string named after the class, an instance of the class, or an instance of the class reflected + * @return boolean + */ + public static function isValidModelClass($class) + { + if ($class instanceof Doctrine_Record) { + $class = get_class($class); + } + + if (is_string($class) && class_exists($class)) { + $class = new ReflectionClass($class); + } + + if ($class instanceof ReflectionClass) { + // Skip the following classes + // - abstract classes + // - not a subclass of Doctrine_Record + // - don't have a setTableDefinition method + if (!$class->isAbstract() && + $class->isSubClassOf('Doctrine_Record') && + $class->hasMethod('setTableDefinition')) { + + return true; + } + } + + return false; + } + + public static function IsReconcKey($sClass, $sAttCode) + { + return (in_array($sAttCode, self::GetReconcKeys($sClass))); + } + + final static public function GetAttributeDef($sClass, $sAttCode) + { + self::_check_subclass($sClass); + return self::$m_aAttribDefs[$sClass][$sAttCode]; + } + + final static public function GetExternalKeys($sClass) + { + $aExtKeys = array(); + foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) + { + if ($oAtt->IsExternalKey()) + { + $aExtKeys[$sAttCode] = $oAtt; + } + } + return $aExtKeys; + } + + final static public function GetExternalFields($sClass, $sKeyAttCode) + { + $aExtFields = array(); + foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt) + { + if ($oAtt->IsExternalField() && ($oAtt->GetKeyAttCode() == $sKeyAttCode)) + { + $aExtFields[] = $oAtt; + } + } + return $aExtFields; + } + + final static public function GetExtKeyFriends($sClass, $sExtKeyAttCode) + { + if (array_key_exists($sExtKeyAttCode, self::$m_aExtKeyFriends[$sClass])) + { + return self::$m_aExtKeyFriends[$sClass][$sExtKeyAttCode]; + } + else + { + return array(); + } + } + + public static function GetLabel($sClass, $sAttCode) + { + $oAttDef = self::GetAttributeDef($sClass, $sAttCode); + if ($oAttDef) return $oAttDef->GetLabel(); + return ""; + } + + public static function GetDescription($sClass, $sAttCode) + { + $oAttDef = self::GetAttributeDef($sClass, $sAttCode); + if ($oAttDef) return $oAttDef->GetDescription(); + return ""; + } + + // Filters of a given class may contain filters defined in a parent class + // - Some filters are a copy of the definition + // - Some filters correspond to the upper class table definition (compound objects) + // (see also attributes definition) + private static $m_aFilterDefs = array(); // array of ("classname" => array filterdef) + private static $m_aFilterOrigins = array(); // array of ("classname" => array of ("attcode"=>"sourceclass")) + + public static function GetClassFilterDefs($sClass) + { + self::_check_subclass($sClass); + return self::$m_aFilterDefs[$sClass]; + } + + final static public function GetClassFilterDef($sClass, $sFilterCode) + { + self::_check_subclass($sClass); + return self::$m_aFilterDefs[$sClass][$sFilterCode]; + } + + public static function GetFilterLabel($sClass, $sFilterCode) + { + $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); + if ($oFilter) return $oFilter->GetLabel(); + return ""; + } + + public static function GetFilterDescription($sClass, $sFilterCode) + { + $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); + if ($oFilter) return $oFilter->GetDescription(); + return ""; + } + + // returns an array of opcode=>oplabel (e.g. "differs from") + public static function GetFilterOperators($sClass, $sFilterCode) + { + $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); + if ($oFilter) return $oFilter->GetOperators(); + return array(); + } + + // returns an opcode + public static function GetFilterLooseOperator($sClass, $sFilterCode) + { + $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); + if ($oFilter) return $oFilter->GetLooseOperator(); + return array(); + } + + public static function GetFilterOpDescription($sClass, $sFilterCode, $sOpCode) + { + $oFilter = self::GetClassFilterDef($sClass, $sFilterCode); + if ($oFilter) return $oFilter->GetOpDescription($sOpCode); + return ""; + } + + public static function GetFilterHTMLInput($sFilterCode) + { + return ""; + } + + // Lists of attributes/search filters + // + private static $m_aListInfos = array(); // array of ("listcode" => various info on the list, common to every classes) + private static $m_aListData = array(); // array of ("classname" => array of "listcode" => list) + // list may be an array of attcode / fltcode + // list may be an array of "groupname" => (array of attcode / fltcode) + + public static function EnumZLists() + { + return array_keys(self::$m_aListInfos); + } + + final static public function GetZListInfo($sListCode) + { + return self::$m_aListInfos[$sListCode]; + } + + public static function GetZListItems($sClass, $sListCode) + { + if (array_key_exists($sClass, self::$m_aListData)) + { + if (array_key_exists($sListCode, self::$m_aListData[$sClass])) + { + return self::$m_aListData[$sClass][$sListCode]; + } + } + $sParentClass = self::GetParentPersistentClass($sClass); + if (empty($sParentClass)) return array(); // nothing for the mother of all classes + // Dig recursively + return self::GetZListItems($sParentClass, $sListCode); + } + + public static function IsAttributeInZList($sClass, $sListCode, $sAttCodeOrFltCode, $sGroup = null) + { + $aZList = self::GetZListItems($sClass, $sListCode); + if (!$sGroup) + { + return (in_array($sAttCodeOrFltCode, $aZList)); + } + return (in_array($sAttCodeOrFltCode, $aZList[$sGroup])); + } + + // + // Relations + // + private static $m_aRelationInfos = array(); // array of ("relcode" => various info on the list, common to every classes) + + public static function EnumRelations() + { + return array_keys(self::$m_aRelationInfos); + } + + public static function EnumRelationProperties($sRelCode) + { + MyHelpers::CheckKeyInArray('relation code', $sRelCode, self::$m_aRelationInfos); + return self::$m_aRelationInfos[$sRelCode]; + } + + final static public function GetRelationProperty($sRelCode, $sProperty) + { + MyHelpers::CheckKeyInArray('relation code', $sRelCode, self::$m_aRelationInfos); + MyHelpers::CheckKeyInArray('relation property', $sProperty, self::$m_aRelationInfos[$sRelCode]); + + return self::$m_aRelationInfos[$sRelCode][$sProperty]; + } + + public static function EnumRelationQueries($sClass, $sRelCode) + { + MyHelpers::CheckKeyInArray('relation code', $sRelCode, self::$m_aRelationInfos); + return call_user_func_array(array($sClass, 'GetRelationQueries'), array($sRelCode)); + } + + // + // Object lifecycle model + // + private static $m_aStates = array(); // array of ("classname" => array of "statecode"=>array('label'=>..., 'description'=>..., attribute_inherit=> attribute_list=>...)) + private static $m_aStimuli = array(); // array of ("classname" => array of ("stimuluscode"=>array('label'=>..., 'description'=>...))) + private static $m_aTransitions = array(); // array of ("classname" => array of ("statcode_from"=>array of ("stimuluscode" => array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD))) + + public static function EnumStates($sClass) + { + if (array_key_exists($sClass, self::$m_aStates)) + { + return self::$m_aStates[$sClass]; + } + else + { + return array(); + } + } + + public static function EnumStimuli($sClass) + { + if (array_key_exists($sClass, self::$m_aStimuli)) + { + return self::$m_aStimuli[$sClass]; + } + else + { + return array(); + } + } + + public static function EnumTransitions($sClass, $sStateCode) + { + if (array_key_exists($sClass, self::$m_aTransitions)) + { + if (array_key_exists($sStateCode, self::$m_aTransitions[$sClass])) + { + return self::$m_aTransitions[$sClass][$sStateCode]; + } + } + return array(); + } + public static function GetAttributeFlags($sClass, $sState, $sAttCode) + { + $iFlags = 0; // By default (if no life cycle) no flag at all + $sStateAttCode = self::GetStateAttributeCode($sClass); + if (!empty($sStateAttCode)) + { + $aStates = MetaModel::EnumStates($sClass); + $aCurrentState = $aStates[$sState]; + if ( (array_key_exists('attribute_list', $aCurrentState)) && (array_key_exists($sAttCode, $aCurrentState['attribute_list'])) ) + { + $iFlags = $aCurrentState['attribute_list'][$sAttCode]; + } + } + return $iFlags; + } + + // + // Allowed values + // + + public static function GetAllowedValues_att($sClass, $sAttCode, $aArgs = array(), $sBeginsWith = '') + { + $oAttDef = self::GetAttributeDef($sClass, $sAttCode); + if (!$oAttDef) return null; + $oValSetDef = $oAttDef->GetValuesDef(); + if (!$oValSetDef) return null; + return $oValSetDef->GetValues($aArgs, $sBeginsWith); + } + + public static function GetAllowedValues_flt($sClass, $sFltCode, $aArgs = array(), $sBeginsWith = '') + { + $oFltDef = self::GetClassFilterDef($sClass, $sFltCode); + if (!$oFltDef) return null; + $oValSetDef = $oFltDef->GetValuesDef(); + if (!$oValSetDef) return null; + return $oValSetDef->GetValues($aArgs, $sBeginsWith); + } + + // + // Businezz model declaration verbs (should be static) + // + + public static function RegisterZList($sListCode, $aListInfo) + { + // Check mandatory params + $aMandatParams = array( + "description" => "detailed (though one line) description of the list", + "type" => "attributes | filters", + ); + foreach($aMandatParams as $sParamName=>$sParamDesc) + { + if (!array_key_exists($sParamName, $aListInfo)) + { + trigger_error("Declaration of list $sListCode - missing parameter $sParamName", E_USER_ERROR); + } + } + + self::$m_aListInfos[$sListCode] = $aListInfo; + } + + public static function RegisterRelation($sRelCode, $aRelationInfo) + { + // Check mandatory params + $aMandatParams = array( + "description" => "detailed (though one line) description of the list", + "verb_down" => "e.g.: 'impacts'", + "verb_up" => "e.g.: 'is impacted by'", + ); + foreach($aMandatParams as $sParamName=>$sParamDesc) + { + if (!array_key_exists($sParamName, $aRelationInfo)) + { + trigger_error("Declaration of relation $sRelCode - missing parameter $sParamName", E_USER_ERROR); + } + } + + self::$m_aRelationInfos[$sRelCode] = $aRelationInfo; + } + + // Must be called once and only once... + public static function InitClasses($sTablePrefix) + { + if (count(self::GetClasses()) > 0) + { + trigger_error("InitClasses should not be called more than once -skipped"); + return; + } + + // Table names must be lower case + self::$m_sTablePrefix = strtolower($sTablePrefix); + + foreach(get_declared_classes() as $sPHPClass) { + if (is_subclass_of($sPHPClass, 'DBObject')) + { + if (method_exists($sPHPClass, 'Init')) + { + call_user_func(array($sPHPClass, 'Init')); + } + } + } + foreach (self::GetClasses() as $sClass) + { + // Compute the fields that will be used to display a pointer to another object + // + self::$m_aExtKeyFriends[$sClass] = array(); + foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) + { + if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) + { + // oAttDef is either + // - an external KEY / FIELD (direct), + // - an external field pointing to an external KEY / FIELD + // - an external field pointing to an external field pointing to.... + + // Get the real external key attribute + // It will be our reference to determine the other ext fields related to the same ext key + $oFinalKeyAttDef = $oAttDef->GetKeyAttDef(EXTKEY_ABSOLUTE); + + self::$m_aExtKeyFriends[$sClass][$sAttCode] = array(); + foreach (self::GetExternalFields($sClass, $oAttDef->GetKeyAttCode($sAttCode)) as $oExtField) + { + // skip : those extfields will be processed as external keys + if ($oExtField->IsExternalKey(EXTKEY_ABSOLUTE)) continue; + + // Note: I could not compare the objects by the mean of '===' + // because they are copied for the inheritance, and the internal references are NOT updated + if ($oExtField->GetKeyAttDef(EXTKEY_ABSOLUTE) == $oFinalKeyAttDef) + { + self::$m_aExtKeyFriends[$sClass][$sAttCode][$oExtField->GetCode()] = $oExtField; + } + } + } + } + + // Add a 'pkey' filter + // + if (array_key_exists('pkey', self::$m_aAttribDefs[$sClass])) + { + trigger_error("Class $sClass, 'pkey' is a reserved keyword, it cannot be used as an attribute code", E_USER_ERROR); + } + if (array_key_exists('pkey', self::$m_aFilterDefs[$sClass])) + { + trigger_error("Class $sClass, 'pkey' is a reserved keyword, it cannot be used as a filter code", E_USER_ERROR); + } + $oFilter = new FilterPrivateKey('pkey', array('pkey_field' => self::DBGetKey($sClass))); + self::$m_aFilterDefs[$sClass]['pkey'] = $oFilter; + self::$m_aFilterOrigins[$sClass]['pkey'] = $sClass; + + // Add a 'class' attribute/filter to the root classes and their children + // + if (!self::IsStandaloneClass($sClass)) + { + if (array_key_exists('finalclass', self::$m_aAttribDefs[$sClass])) + { + trigger_error("Class $sClass, 'finalclass' is a reserved keyword, it cannot be used as an attribute code", E_USER_ERROR); + } + if (array_key_exists('finalclass', self::$m_aFilterDefs[$sClass])) + { + trigger_error("Class $sClass, 'finalclass' is a reserved keyword, it cannot be used as a filter code", E_USER_ERROR); + } + $sClassAttCode = 'finalclass'; + $sRootClass = self::GetRootClass($sClass); + $sDbFinalClassField = self::DBGetClassField($sRootClass); + $oClassAtt = new AttributeString($sClassAttCode, array( + "label"=>"Class", + "description"=>"Real (final) object class", + "allowed_values"=>null, + "sql"=>$sDbFinalClassField, + "default_value"=>$sClass, + "is_null_allowed"=>false, + "depends_on"=>array() + )); + self::$m_aAttribDefs[$sClass][$sClassAttCode] = $oClassAtt; + self::$m_aAttribOrigins[$sClass][$sClassAttCode] = $sRootClass; + + $oClassFlt = new FilterFromAttribute($oClassAtt); + self::$m_aFilterDefs[$sClass][$sClassAttCode] = $oClassFlt; + self::$m_aFilterOrigins[$sClass][$sClassAttCode] = self::GetRootClass($sClass); + } + } + + } + + // To be overriden, must be called for any object class (optimization) + public static function Init() + { + // In fact it is an ABSTRACT function, but this is not compatible with the fact that it is STATIC (error in E_STRICT interpretation) + } + // To be overloaded by biz model declarations + public static function GetRelationQueries($sRelCode) + { + // In fact it is an ABSTRACT function, but this is not compatible with the fact that it is STATIC (error in E_STRICT interpretation) + return array(); + } + + public static function Init_Params($aParams) + { + // Check mandatory params + $aMandatParams = array( + "category" => "group classes by modules defining their visibility in the UI", + "name" => "internal class name, may be different than the PHP class name", + "description" => "detailed (though one line) description of the class", + "key_type" => "autoincrement | string", + "key_label" => "if set, then display the key as an attribute", + "name_attcode" => "define wich attribute is the class name, may be an inherited attribute", + "state_attcode" => "define wich attribute is representing the state (object lifecycle)", + "reconc_keys" => "define the attributes that will 'almost uniquely' identify an object in batch processes", + "db_table" => "database table", + "db_key_field" => "database field which is the key", + "db_finalclass_field" => "database field wich is the reference to the actual class of the object, considering that this will be a compound class", + ); + + $sClass = self::GetCallersPHPClass("Init"); + if (!array_key_exists("name", $aParams)) + { + trigger_error("Declaration of class $sClass: missing name ({$aMandatParams["name"]})", E_USER_ERROR); + } + + foreach($aMandatParams as $sParamName=>$sParamDesc) + { + if (!array_key_exists($sParamName, $aParams)) + { + trigger_error("Declaration of class $sClass - missing parameter $sParamName", E_USER_ERROR); + } + } + + $aCategories = explode(',', $aParams['category']); + foreach ($aCategories as $sCategory) + { + self::$m_Category2Class[$sCategory][] = $sClass; + } + self::$m_Category2Class[''][] = $sClass; // all categories, include this one + + + self::$m_aRootClasses[$sClass] = $sClass; // first, let consider that I am the root... updated on inheritance + self::$m_aParentClasses[$sClass] = array(); + self::$m_aChildClasses[$sClass] = array(); + + self::$m_aClassParams[$sClass]= $aParams; + + self::$m_aAttribDefs[$sClass] = array(); + self::$m_aAttribOrigins[$sClass] = array(); + self::$m_aExtKeyFriends[$sClass] = array(); + self::$m_aFilterDefs[$sClass] = array(); + self::$m_aFilterOrigins[$sClass] = array(); + } + + protected static function object_array_mergeclone($aSource1, $aSource2) + { + $aRes = array(); + foreach ($aSource1 as $key=>$object) + { + $aRes[$key] = clone $object; + } + foreach ($aSource2 as $key=>$object) + { + $aRes[$key] = clone $object; + } + return $aRes; + } + + public static function Init_InheritAttributes($sSourceClass = null) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + if (empty($sSourceClass)) + { + // Default: inherit from parent class + $sSourceClass = self::GetParentPersistentClass($sTargetClass); + if (empty($sSourceClass)) return; // no attributes for the mother of all classes + } + if (isset(self::$m_aAttribDefs[$sSourceClass])) + { + if (!isset(self::$m_aAttribDefs[$sTargetClass])) + { + self::$m_aAttribDefs[$sTargetClass] = array(); + self::$m_aAttribOrigins[$sTargetClass] = array(); + } + self::$m_aAttribDefs[$sTargetClass] = self::object_array_mergeclone(self::$m_aAttribDefs[$sTargetClass], self::$m_aAttribDefs[$sSourceClass]); + self::$m_aAttribOrigins[$sTargetClass] = array_merge(self::$m_aAttribOrigins[$sTargetClass], self::$m_aAttribOrigins[$sSourceClass]); + } + // later on, we might consider inheritance in different ways !!! + //if (strlen(self::DBGetTable($sSourceClass)) != 0) + if (self::HasFinalClassField(self::$m_aRootClasses[$sSourceClass])) + { + // Inherit the root class + self::$m_aRootClasses[$sTargetClass] = self::$m_aRootClasses[$sSourceClass]; + } + else + { + // I am a root class, standalone as well ! + // ???? + //self::$m_aRootClasses[$sTargetClass] = $sTargetClass; + } + self::$m_aParentClasses[$sTargetClass] += self::$m_aParentClasses[$sSourceClass]; + self::$m_aParentClasses[$sTargetClass][] = $sSourceClass; + // I am the child of each and every parent... + foreach(self::$m_aParentClasses[$sTargetClass] as $sAncestorClass) + { + self::$m_aChildClasses[$sAncestorClass][] = $sTargetClass; + } + } + public static function Init_OverloadAttributeParams($sAttCode, $aParams) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + + if (!self::IsValidAttCode($sTargetClass, $sAttCode)) + { + trigger_error("Could not overload '$sAttCode', expecting a code from {".implode(", ", self::GetAttributesList($sTargetClass))."}"); + } + self::$m_aAttribDefs[$sTargetClass][$sAttCode]->OverloadParams($aParams); + } + public static function Init_AddAttribute(AttributeDefinition $oAtt) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + self::$m_aAttribDefs[$sTargetClass][$oAtt->GetCode()] = $oAtt; + self::$m_aAttribOrigins[$sTargetClass][$oAtt->GetCode()] = $sTargetClass; + // Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used + + // Specific case of external fields: + // I wanted to simplify the syntax of the declaration of objects in the biz model + // Therefore, the reference to the host class is set there + $oAtt->SetHostClass($sTargetClass); + } + + public static function Init_InheritFilters($sSourceClass = null) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + if (empty($sSourceClass)) + { + // Default: inherit from parent class + $sSourceClass = self::GetParentPersistentClass($sTargetClass); + if (empty($sSourceClass)) return; // no filters for the mother of all classes + } + if (isset(self::$m_aFilterDefs[$sSourceClass])) + { + if (!isset(self::$m_aFilterDefs[$sTargetClass])) + { + self::$m_aFilterDefs[$sTargetClass] = array(); + self::$m_aFilterOrigins[$sTargetClass] = array(); + } + + foreach (self::$m_aFilterDefs[$sSourceClass] as $sFltCode=>$oFilter) + { + if ($oFilter instanceof FilterFromAttribute) + { + // In that case, cloning is not enough: + // we must ensure that we will point to the correct + // attribute definition (in case some properties are overloaded) + $oAttDef1 = $oFilter->__GetRefAttribute(); + $oAttDef2 = self::GetAttributeDef($sTargetClass, $oAttDef1->GetCode()); + $oNewFilter = new FilterFromAttribute($oAttDef2); + } + else + { + $oNewFilter = clone $oFilter; + } + self::$m_aFilterDefs[$sTargetClass][$sFltCode] = $oNewFilter; + } + + self::$m_aFilterOrigins[$sTargetClass] = array_merge(self::$m_aFilterOrigins[$sTargetClass], self::$m_aFilterOrigins[$sSourceClass]); + } + } + + public static function Init_OverloadFilterParams($sFltCode, $aParams) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + + if (!self::IsValidFilterCode($sTargetClass, $sFltCode)) + { + trigger_error("Could not overload '$sFltCode', expecting a code from {".implode(", ", self::GetFiltersList($sTargetClass))."}"); + } + self::$m_aFilterDefs[$sTargetClass][$sFltCode]->OverloadParams($aParams); + } + + public static function Init_AddFilter(FilterDefinition $oFilter) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + self::$m_aFilterDefs[$sTargetClass][$oFilter->GetCode()] = $oFilter; + self::$m_aFilterOrigins[$sTargetClass][$oFilter->GetCode()] = $sTargetClass; + // Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used + } + public static function Init_AddFilterFromAttribute($sAttCode) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + + $oAttDef = self::GetAttributeDef($sTargetClass, $sAttCode); + + $sFilterCode = $sAttCode; + $oNewFilter = new FilterFromAttribute($oAttDef); + self::$m_aFilterDefs[$sTargetClass][$sFilterCode] = $oNewFilter; + + if ($oAttDef->IsExternalField()) + { + $sKeyAttCode = $oAttDef->GetKeyAttCode(); + $oKeyDef = self::GetAttributeDef($sTargetClass, $sKeyAttCode); + self::$m_aFilterOrigins[$sTargetClass][$sFilterCode] = $oKeyDef->GetTargetClass(); + } + else + { + self::$m_aFilterOrigins[$sTargetClass][$sFilterCode] = $sTargetClass; + } + // Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used + } + + public static function Init_SetZListItems($sListCode, $aItems) + { + MyHelpers::CheckKeyInArray('list code', $sListCode, self::$m_aListInfos); + + $sTargetClass = self::GetCallersPHPClass("Init"); + self::$m_aListData[$sTargetClass][$sListCode] = $aItems; + } + + public static function Init_DefineState($sStateCode, $aStateDef) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + if (is_null($aStateDef['attribute_list'])) $aStateDef['attribute_list'] = array(); + + $sParentState = $aStateDef['attribute_inherit']; + if (!empty($sParentState)) + { + // Inherit from the given state (must be defined !) + $aToInherit = self::$m_aStates[$sTargetClass][$sParentState]; + // The inherited configuration could be overriden + $aStateDef['attribute_list'] = array_merge($aToInherit, $aStateDef['attribute_list']); + } + self::$m_aStates[$sTargetClass][$sStateCode] = $aStateDef; + + // by default, create an empty set of transitions associated to that state + self::$m_aTransitions[$sTargetClass][$sStateCode] = array(); + } + + public static function Init_DefineStimulus($sStimulusCode, $oStimulus) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + self::$m_aStimuli[$sTargetClass][$sStimulusCode] = $oStimulus; + } + + public static function Init_DefineTransition($sStateCode, $sStimulusCode, $aTransitionDef) + { + $sTargetClass = self::GetCallersPHPClass("Init"); + if (is_null($aTransitionDef['actions'])) $aTransitionDef['actions'] = array(); + self::$m_aTransitions[$sTargetClass][$sStateCode][$sStimulusCode] = $aTransitionDef; + } + + public static function Init_InheritLifecycle($sSourceClass = '') + { + $sTargetClass = self::GetCallersPHPClass("Init"); + if (empty($sSourceClass)) + { + // Default: inherit from parent class + $sSourceClass = self::GetParentPersistentClass($sTargetClass); + if (empty($sSourceClass)) return; // no attributes for the mother of all classes + } + + self::$m_aClassParams[$sTargetClass]["state_attcode"] = self::$m_aClassParams[$sSourceClass]["state_attcode"]; + self::$m_aStates[$sTargetClass] = clone self::$m_aStates[$sSourceClass]; + self::$m_aStimuli[$sTargetClass] = clone self::$m_aStimuli[$sSourceClass]; + self::$m_aTransitions[$sTargetClass] = clone self::$m_aTransitions[$sSourceClass]; + } + + // + // Static API + // + + public static function GetRootClass($sClass = null) + { + self::_check_subclass($sClass); + return self::$m_aRootClasses[$sClass]; + } + public static function IsRootClass($sClass) + { + self::_check_subclass($sClass); + return (self::GetRootClass($sClass) == $sClass); + } + public static function EnumParentClasses($sClass) + { + self::_check_subclass($sClass); + return self::$m_aParentClasses[$sClass]; + } + public static function EnumChildClasses($sClass, $iOption = ENUM_CHILD_CLASSES_EXCLUDETOP) + { + self::_check_subclass($sClass); + + $aRes = self::$m_aChildClasses[$sClass]; + if ($iOption != ENUM_CHILD_CLASSES_EXCLUDETOP) + { + // Add it to the list + $aRes[] = $sClass; + } + return $aRes; + } + + public static function EnumCategories() + { + return array_keys(self::$m_Category2Class); + } + + // Note: use EnumChildClasses to take the compound objects into account + public static function GetSubclasses($sClass) + { + self::_check_subclass($sClass); + $aSubClasses = array(); + foreach(get_declared_classes() as $sSubClass) { + if (is_subclass_of($sSubClass, $sClass)) + { + $aSubClasses[] = $sSubClass; + } + } + return $aSubClasses; + } + public static function GetClasses($sCategory = '') + { + if (array_key_exists($sCategory, self::$m_Category2Class)) + { + return self::$m_Category2Class[$sCategory]; + } + + if (count(self::$m_Category2Class) > 0) + { + trigger_error("unkown class category '$sCategory', expecting a value in {".implode(', ', array_keys(self::$m_Category2Class))."}"); + } + return array(); + } + + public static function IsAbstract($sClass) + { + if (strlen(self::DBGetTable($sClass)) == 0) return true; + return false; + } + + public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array()) + { + $aTranslation = array(); + $aClassAliases = array(); + $aTableAliases = array(); + $oConditionTree = $oFilter->GetCriteria(); + $oSelect = self::MakeQuery($oFilter->GetClassAlias(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter); + + // Check the order by specification + foreach ($aOrderBy as $sFieldAlias => $bAscending) + { + MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetClass())); + if (!is_bool($bAscending)) + { + trigger_error("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value"); + } + } + if (empty($aOrderBy)) + { + $sNameAttCode = self::GetNameAttributeCode($oFilter->GetClass()); + if (!empty($sNameAttCode)) + { + // By default, simply order on the "name" attribute, ascending + $aOrderBy = array($sNameAttCode => true); + } + } + + //MyHelpers::var_dump_html($oSelect->RenderSelect($aOrderBy)); + return $oSelect->RenderSelect($aOrderBy); + } + + public static function MakeDeleteQuery(DBObjectSearch $oFilter) + { + $aTranslation = array(); + $aClassAliases = array(); + $aTableAliases = array(); + $oConditionTree = $oFilter->GetCriteria(); + $oSelect = self::MakeQuery($oFilter->GetClassAlias(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter); + return $oSelect->RenderDelete(); + } + + public static function MakeUpdateQuery(DBObjectSearch $oFilter, $aValues) + { + // $aValues is an array of $sAttCode => $value + $aTranslation = array(); + $aClassAliases = array(); + $aTableAliases = array(); + $oConditionTree = $oFilter->GetCriteria(); + $oSelect = self::MakeQuery($oFilter->GetClassAlias(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, array(), $aValues); + return $oSelect->RenderUpdate(); + } + + private static function MakeQuery($sGlobalTargetAlias, &$oConditionTree, &$aClassAliases, &$aTableAliases, &$aTranslation, DBObjectSearch $oFilter, $aExpectedAtts = array(), $aValues = array()) + { + // Note: query class might be different than the class of the filter + // -> this occurs when we are linking our class to an external class (referenced by, or pointing to) + // $aExpectedAtts is an array of sAttCode=>sAlias + $sClass = $oFilter->GetClass(); + $sClassAlias = $oFilter->GetClassAlias(); + + $bIsOnQueriedClass = ($sClassAlias == $sGlobalTargetAlias); + if ($bIsOnQueriedClass) + { + $aClassAliases = array_merge($aClassAliases, $oFilter->GetClasses()); + } + + self::DbgTrace("Entering: ".$oFilter->ToSibuSQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY").", expectedatts=".count($aExpectedAtts).": ".implode(",", $aExpectedAtts)); + + $sRootClass = self::GetRootClass($sClass); + $sKeyField = self::DBGetKey($sClass); + + if (empty($aExpectedAtts) && $bIsOnQueriedClass) + { + // default to the whole list of attributes + the very std pkey/finalclass + $aExpectedAtts['pkey'] = 'pkey'; + foreach (self::GetAttributesList($sClass) as $sAttCode) + { + $aExpectedAtts[$sAttCode] = $sAttCode; // alias == attcode + } + } + + // Compute a clear view of external keys, and external attributes + // Build the list of external keys: + // -> ext keys required by a closed join ??? + // -> ext keys mentionned in a 'pointing to' condition + // -> ext keys required for an external field + // + $aExtKeys = array(); // array of sTableClass => array of (sAttCode (keys) => array of (sAttCode (fields)=> oAttDef)) + // + // Optimization: could be computed once for all (cached) + // Could be done in MakeQuerySingleTable ??? + // + + if ($bIsOnQueriedClass) + { + // Get all Ext keys for the queried class (??) + foreach(self::GetKeysList($sClass) as $sKeyAttCode) + { + $sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode]; + $aExtKeys[$sKeyTableClass][$sKeyAttCode] = array(); + } + } + // Get all Ext keys used by the filter + foreach ($oFilter->GetCriteria_PointingTo() as $sKeyAttCode => $trash) + { + $sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode]; + $aExtKeys[$sKeyTableClass][$sKeyAttCode] = array(); + } + // Add the ext fields used in the select (eventually adds an external key) + foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsExternalField()) + { + $sKeyAttCode = $oAttDef->GetKeyAttCode(); + if (array_key_exists($sAttCode, $aExpectedAtts) || $oConditionTree->RequiresField($sClassAlias, $sAttCode)) + { + // Add the external attribute + $sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode]; + $aExtKeys[$sKeyTableClass][$sKeyAttCode][$sAttCode] = $oAttDef; + } + } + } + + // First query built upon on the leaf (ie current) class + // + self::DbgTrace("Main (=leaf) class, call MakeQuerySingleTable()"); + $oSelectBase = self::MakeQuerySingleTable($sGlobalTargetAlias, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, $sClass, $aExpectedAtts, $aExtKeys, $aValues); + + // Then we join the queries of the eventual parent classes (compound model) + foreach(self::EnumParentClasses($sClass) as $sParentClass) + { + if (self::DBGetTable($sParentClass) == "") continue; + self::DbgTrace("Parent class: $sParentClass... let's call MakeQuerySingleTable()"); + $oSelectParentTable = self::MakeQuerySingleTable($sGlobalTargetAlias, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter, $sParentClass, $aExpectedAtts, $aExtKeys, $aValues); + $oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, self::DBGetKey($sParentClass)); + } + + // Filter on objects referencing me + foreach ($oFilter->GetCriteria_ReferencedBy() as $sForeignClass => $aKeysAndFilters) + { + $sForeignClassAlias = $oFilter->GetClassAlias(); + foreach ($aKeysAndFilters as $sForeignKeyAttCode => $oForeignFilter) + { + $oForeignKeyAttDef = self::GetAttributeDef($sForeignClass, $sForeignKeyAttCode); + + // We don't want any attribute from the foreign class, just filter on an inner join + $aExpAtts = array(); + + self::DbgTrace("Referenced by foreign key: $sForeignKeyAttCode... let's call MakeQuery()"); + //self::DbgTrace($oForeignFilter); + //self::DbgTrace($oForeignFilter->ToSibuSQL()); + //self::DbgTrace($oSelectForeign); + //self::DbgTrace($oSelectForeign->RenderSelect(array())); + $oSelectForeign = self::MakeQuery($sGlobalTargetAlias, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oForeignFilter, $aExpAtts); + + $sForeignKeyField = $oForeignKeyAttDef->GetSQLExpr(); + $oSelectBase->AddInnerJoin($oSelectForeign, $sKeyField, $sForeignKeyField); + } + } + + // Filter on related objects + // + foreach ($oFilter->GetCriteria_RelatedTo() as $aCritInfo) + { + $oSubFilter = $aCritInfo['flt']; + $sRelCode = $aCritInfo['relcode']; + $iMaxDepth = $aCritInfo['maxdepth']; + + // Get the starting point objects + $oStartSet = new CMDBObjectSet($oSubFilter); + + // Get the objects related to those objects... recursively... + $aRelatedObjs = $oStartSet->GetRelatedObjects($sRelCode, $iMaxDepth); + $aRestriction = array_key_exists($sRootClass, $aRelatedObjs) ? $aRelatedObjs[$sRootClass] : array(); + + // #@# todo - related objects and expressions... + // Create condition + if (count($aRestriction) > 0) + { + $oSelectBase->AddCondition($sKeyField.' IN ('.implode(', ', CMDBSource::Quote(array_keys($aRestriction), true)).')'); + } + else + { + // Quick N'dirty -> generate an empty set + $oSelectBase->AddCondition('false'); + } + } + + // Translate the conditions... and go + // + if ($bIsOnQueriedClass) + { + $oConditionTranslated = $oConditionTree->Translate($aTranslation); + $oSelectBase->SetCondition($oConditionTranslated); + } + + // That's all... cross fingers and we'll get some working query + + //MyHelpers::var_dump_html($oSelectBase, true); + //MyHelpers::var_dump_html($oSelectBase->RenderSelect(), true); + if (self::$m_bDebugQuery) $oSelectBase->DisplayHtml(); + return $oSelectBase; + } + + protected static function MakeQuerySingleTable($sGlobalTargetAlias, &$oConditionTree, &$aClassAliases, &$aTableAliases, &$aTranslation, $oFilter, $sTableClass, $aExpectedAtts, $aExtKeys, $aValues) + { + // $aExpectedAtts is an array of sAttCode=>sAlias + // $aExtKeys is an array of sTableClass => array of (sAttCode (keys) => array of sAttCode (fields)) + + // Prepare the query for a single table (compound objects) + // Ignores the items (attributes/filters) that are not on the target table + // Perform an (inner or left) join for every external key (and specify the expected fields) + // + // Returns an SQLQuery + // + $sTargetClass = $oFilter->GetClass(); + $sTargetAlias = $oFilter->GetClassAlias(); + $sTable = self::DBGetTable($sTableClass); + $sTableAlias = self::GenerateUniqueAlias($aTableAliases, $sTable, $sTable); + + $bIsOnQueriedClass = ($sTargetAlias == $sGlobalTargetAlias); + + self::DbgTrace("Entering: tableclass=$sTableClass, filter=".$oFilter->ToSibuSQL().", ".($bIsOnQueriedClass ? "MAIN" : "SECONDARY").", expectedatts=".count($aExpectedAtts).": ".implode(",", $aExpectedAtts)); + + // 1 - SELECT and UPDATE + // + // Note: no need for any values nor fields for foreign Classes (ie not the queried Class) + // + $aSelect = array(); + $aUpdateValues = array(); + + // 1/a - Get the key + // + if ($bIsOnQueriedClass) + { + $aSelect[$aExpectedAtts['pkey']] = new FieldExpression(self::DBGetKey($sTableClass), $sTableAlias); + } + // We need one pkey to be the key, let's take the one corresponding to the leaf + if ($sTableClass == $sTargetClass) + { + $aTranslation[$sTargetAlias]['pkey'] = array($sTableAlias, self::DBGetKey($sTableClass)); + } + + // 1/b - Get the other attributes + // + foreach(self::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) + { + // Skip this attribute if not defined in this table + if (self::$m_aAttribOrigins[$sTargetClass][$sAttCode] != $sTableClass) continue; + + // Skip this attribute if not writable (means that it does not correspond + if (count($oAttDef->DBGetUsedFields()) == 0) continue; + + // Update... + // + if ($bIsOnQueriedClass && array_key_exists($sAttCode, $aValues)) + { + assert ($oAttDef->IsDirectField()); + // Later, we'll have to use $oAttDef->GetDBField(); + $aUpdateValues[$oAttDef->GetSQLExpr()] = $oAttDef->RealValueToSQLValue($aValues[$sAttCode]); + } + + // Select... + // + // Skip, if a list of fields has been specified and it is not there + if (!array_key_exists($sAttCode, $aExpectedAtts)) continue; + $sAttAlias = $aExpectedAtts[$sAttCode]; + + if ($oAttDef->IsExternalField()) + { + // skip, this will be handled in the joined tables + } + else + { + // standard field, or external key + // add it to the output + $aSelect[$sAttAlias] = new FieldExpression($oAttDef->GetSQLExpr(), $sTableAlias); + } + } + + // 2 - WHERE + // + foreach(self::$m_aFilterDefs[$sTargetClass] as $sFltCode => $oFltAtt) + { + // Skip pkey + // no, this is a bug now! ?!?!? + // if ($sFltCode == 'pkey') continue; + + // Skip this filter if not defined in this table + if (self::$m_aFilterOrigins[$sTargetClass][$sFltCode] != $sTableClass) continue; + + // #@# todo - aller plus loin... a savoir que la table de translation doit contenir une "Expression" + // non-sens: $aTranslation[$sTargetAlias][$sFltCode] = array($sTableAlias, $oFltAtt->GetFilterSQLExpr(opcode, operand)); + $aTranslation[$sTargetAlias][$sFltCode] = array($sTableAlias, $oFltAtt->TemporaryGetSQLCol()); + } + + // #@# todo - See what a full text search condition should be + // 2' - WHERE / Full text search condition + // + if ($bIsOnQueriedClass) + { + $aFullText = $oFilter->GetCriteria_FullText(); + } + else + { + // Pourquoi ??? + $aFullText = array(); + } + + // 3 - The whole stuff, for this table only + // + $oSelectBase = new SQLQuery($sTable, $sTableAlias, $aSelect, null, $aFullText, $bIsOnQueriedClass, $aUpdateValues); + + // 4 - The external keys -> joins... + // + if (array_key_exists($sTableClass, $aExtKeys)) + { + foreach ($aExtKeys[$sTableClass] as $sKeyAttCode => $aExtFields) + { + $oKeyAttDef = self::GetAttributeDef($sTargetClass, $sKeyAttCode); + + $oExtFilter = $oFilter->GetCriteria_PointingTo($sKeyAttCode); + + // In case the join was not explicitely defined in the filter, + // we need to do it now + if (empty($oExtFilter)) + { + $sKeyClass = $oKeyAttDef->GetTargetClass(); + $sKeyClassAlias = self::GenerateUniqueAlias($aClassAliases, $sKeyClass.'_'.$sKeyAttCode, $sKeyClass); + $oExtFilter = new DBObjectSearch($sKeyClass, $sKeyClassAlias); + } + else + { + // The aliases should not conflict because normalization occured while building the filter + $sKeyClass = $oExtFilter->GetClass(); + $sKeyClassAlias = $oExtFilter->GetClassAlias(); + + // Note: there is no search condition in $oExtFilter, because normalization did merge the condition onto the top of the filter tree + } + + // Specify expected attributes for the target class query + // ... and use the current alias ! + $aExpAtts = array(); + $aIntermediateTranslation = array(); + foreach($aExtFields as $sAttCode => $oAtt) + { + + $sExtAttCode = $oAtt->GetExtAttCode(); + if (array_key_exists($sAttCode, $aExpectedAtts)) + { + // Request this attribute... transmit the alias ! + $aExpAtts[$sExtAttCode] = $aExpectedAtts[$sAttCode]; + } + // Translate mainclass.extfield => remoteclassalias.remotefieldcode + $oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode); + $sRemoteAttExpr = $oRemoteAttDef->GetSQLExpr(); + $aIntermediateTranslation[$sTargetAlias][$sAttCode] = array($sKeyClassAlias, $sRemoteAttExpr); + //#@# debug - echo "

$sTargetAlias.$sAttCode to $sKeyClassAlias.$sRemoteAttExpr (class: $sKeyClass)

\n"; + } + $oConditionTree = $oConditionTree->Translate($aIntermediateTranslation, false); + + self::DbgTrace("External key $sKeyAttCode (class: $sKeyClass), call MakeQuery()"); + $oSelectExtKey = self::MakeQuery($sGlobalTargetAlias, $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oExtFilter, $aExpAtts); + + $sLocalKeyField = $oKeyAttDef->GetSQLExpr(); + $sExternalKeyField = self::DBGetKey($sKeyClass); + self::DbgTrace("External key $sKeyAttCode, Join on $sLocalKeyField = $sExternalKeyField"); + if ($oKeyAttDef->IsNullAllowed()) + { + $oSelectBase->AddLeftJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField); + } + else + { + $oSelectBase->AddInnerJoin($oSelectExtKey, $sLocalKeyField, $sExternalKeyField); + } + } + } + + //MyHelpers::var_dump_html($oSelectBase->RenderSelect()); + return $oSelectBase; + } + + public static function GenerateUniqueAlias(&$aAliases, $sNewName, $sRealName, $iTentative = 0) + { + // Algo: Build an alias, then check it amongst the contents of $aAliases + + if ($iTentative == 0) $sProposedAlias = $sNewName; + else $sProposedAlias = $sNewName.$iTentative; + + foreach($aAliases as $sAlias=>$sNameWeDontCare) + { + // If the name is already used, then recursively try to get another one + if ($sProposedAlias == $sAlias) return self::GenerateUniqueAlias($aAliases, $sNewName, $sRealName, $iTentative + 1); + } + + // The proposed alias has been proven to be unique + // Record it and return its value + $aAliases[$sProposedAlias] = $sRealName; + return $sProposedAlias; + } + + public static function CheckDefinitions() + { + if (count(self::GetClasses()) == 0) + { + trigger_error("MetaModel::InitClasses() has not been called, or no class has been declared ?!?!"); + exit; + } + + $aErrors = array(); + $aSugFix = array(); + foreach (self::GetClasses() as $sClass) + { + if (self::IsAbstract($sClass)) continue; + + // Check that SQL names are lower case (case is forced lowercase in the DB) + $sTable = self::DBGetTable($sClass); + $sKeyField = self::DBGetKey($sClass); + if (!Str::islowcase($sTable)) + { + $aErrors[$sClass][] = "Table name must be lower case (current value is '$sTable')"; + $aSugFix[$sClass][] = ""; + } + //if (!Str::islowcase($sKeyField)) + //{ + // $aErrors[$sClass][] = "Table name must be lower case (current value is '$sKeyField')"; + // $aSugFix[$sClass][] = ""; + //} + + $sNameAttCode = self::GetNameAttributeCode($sClass); + if (empty($sNameAttCode)) + { + // let's try this !!! + // $aErrors[$sClass][] = "Missing value for name definition: the framework will (should...) replace it by the pkey"; + // $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass)); + } + else if(!self::IsValidAttCode($sClass, $sNameAttCode)) + { + $aErrors[$sClass][] = "Unkown attribute code '".$sNameAttCode."' for the name definition"; + $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass)); + } + + foreach(self::GetReconcKeys($sClass) as $sReconcKeyAttCode) + if (!empty($sReconcKeyAttCode) && !self::IsValidAttCode($sClass, $sReconcKeyAttCode)) + { + $aErrors[$sClass][] = "Unkown attribute code '".$sReconcKeyAttCode."' in the list of reconciliation keys"; + $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass)); + } + + foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + { + // It makes no sense to check the attributes again and again in the subclasses + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; + + if ($oAttDef->IsExternalKey()) + { + if (!self::IsValidClass($oAttDef->GetTargetClass())) + { + $aErrors[$sClass][] = "Unkown class '".$oAttDef->GetTargetClass()."' for the external key '$sAttCode'"; + $aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetClasses())."}"; + } + } + elseif ($oAttDef->IsExternalField()) + { + $sKeyAttCode = $oAttDef->GetKeyAttCode(); + if (!self::IsValidAttCode($sClass, $sKeyAttCode) || !self::IsValidKeyAttCode($sClass, $sKeyAttCode)) + { + $aErrors[$sClass][] = "Unkown key attribute code '".$sKeyAttCode."' for the external field $sAttCode"; + $aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetKeysList($sClass))."}"; + } + else + { + $oKeyAttDef = self::GetAttributeDef($sClass, $sKeyAttCode); + $sTargetClass = $oKeyAttDef->GetTargetClass(); + $sExtAttCode = $oAttDef->GetExtAttCode(); + if (!self::IsValidAttCode($sTargetClass, $sExtAttCode)) + { + $aErrors[$sClass][] = "Unkown key attribute code '".$sExtAttCode."' for the external field $sAttCode"; + $aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetKeysList($sTargetClass))."}"; + } + } + } + else // standard attributes + { + // Check that the default values definition is a valid object! + $oValSetDef = $oAttDef->GetValuesDef(); + if (!is_null($oValSetDef) && !$oValSetDef instanceof ValueSetDefinition) + { + $aErrors[$sClass][] = "Allowed values for attribute $sAttCode is not of the relevant type"; + $aSugFix[$sClass][] = "Please set it as an instance of a ValueSetDefinition object."; + } + else + { + // Default value must be listed in the allowed values (if defined) + $aAllowedValues = self::GetAllowedValues_att($sClass, $sAttCode); + if (!is_null($aAllowedValues)) + { + $sDefaultValue = $oAttDef->GetDefaultValue(); + if (!array_key_exists($sDefaultValue, $aAllowedValues)) + { + $aErrors[$sClass][] = "Default value '".$sDefaultValue."' for attribute $sAttCode is not an allowed value"; + $aSugFix[$sClass][] = "Please pickup the default value out of {'".implode(", ", array_keys($aAllowedValues))."'}"; + } + } + } + } + // Check dependencies + if ($oAttDef->IsWritable()) + { + foreach ($oAttDef->GetPrerequisiteAttributes() as $sDependOnAttCode) + { + if (!self::IsValidAttCode($sClass, $sDependOnAttCode)) + { + $aErrors[$sClass][] = "Unkown attribute code '".$sDependOnAttCode."' in the list of prerequisite attributes"; + $aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass)); + } + } + } + } + foreach(self::GetClassFilterDefs($sClass) as $sFltCode=>$oFilterDef) + { + if (method_exists($oFilterDef, '__GetRefAttribute')) + { + $oAttDef = $oFilterDef->__GetRefAttribute(); + if (!self::IsValidAttCode($sClass, $oAttDef->GetCode())) + { + $aErrors[$sClass][] = "Wrong attribute code '".$oAttDef->GetCode()."' (wrong class) for the \"basic\" filter $sFltCode"; + $aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}"; + } + } + } + + // Lifecycle + // + $sStateAttCode = self::GetStateAttributeCode($sClass); + if (strlen($sStateAttCode) > 0) + { + // Lifecycle - check that the state attribute does exist as an attribute + if (!self::IsValidAttCode($sClass, $sStateAttCode)) + { + $aErrors[$sClass][] = "Unkown attribute code '".$sStateAttCode."' for the state definition"; + $aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}"; + } + else + { + // Lifecycle - check that there is a value set constraint on the state attribute + $aAllowedValuesRaw = self::GetAllowedValues_att($sClass, $sStateAttCode); + $aStates = array_keys(self::EnumStates($sClass)); + if (is_null($aAllowedValuesRaw)) + { + $aErrors[$sClass][] = "Attribute '".$sStateAttCode."' will reflect the state of the object. It must be restricted to a set of values"; + $aSugFix[$sClass][] = "Please define its allowed_values property as [new ValueSetEnum('".implode(", ", $aStates)."')]"; + } + else + { + $aAllowedValues = array_keys($aAllowedValuesRaw); + + // Lifecycle - check the the state attribute allowed values are defined states + foreach($aAllowedValues as $sValue) + { + if (!in_array($sValue, $aStates)) + { + $aErrors[$sClass][] = "Attribute '".$sStateAttCode."' (object state) has an allowed value ($sValue) which is not a known state"; + $aSugFix[$sClass][] = "You may define its allowed_values property as [new ValueSetEnum('".implode(", ", $aStates)."')], or reconsider the list of states"; + } + } + + // Lifecycle - check that defined states are allowed values + foreach($aStates as $sStateValue) + { + if (!in_array($sStateValue, $aAllowedValues)) + { + $aErrors[$sClass][] = "Attribute '".$sStateAttCode."' (object state) has a state ($sStateValue) which is not an allowed value"; + $aSugFix[$sClass][] = "You may define its allowed_values property as [new ValueSetEnum('".implode(", ", $aStates)."')], or reconsider the list of states"; + } + } + } + + // Lifcycle - check that the action handlers are defined + foreach (self::EnumStates($sClass) as $sStateCode => $aStateDef) + { + foreach(self::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef) + { + foreach ($aTransitionDef['actions'] as $sActionHandler) + { + if (!method_exists($sClass, $sActionHandler)) + { + $aErrors[$sClass][] = "Unknown function '$sActionHandler' in transition [$sStateCode/$sStimulusCode] for state attribute '$sStateAttCode'"; + $aSugFix[$sClass][] = "Specify a function which prototype is in the form [public function $sActionHandler(\$sStimulusCode){return true;}]"; + } + } + } + } + } + } + + // ZList + // + foreach(self::EnumZLists() as $sListCode) + { + foreach (self::GetZListItems($sClass, $sListCode) as $sMyAttCode) + { + if (!self::IsValidAttCode($sClass, $sMyAttCode)) + { + $aErrors[$sClass][] = "Unkown attribute code '".$sMyAttCode."' from ZList '$sListCode'"; + $aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}"; + } + } + } + } + if (count($aErrors) > 0) + { + echo "
"; + echo "

Business model inconsistencies have been found

\n"; + // #@# later -> this is the responsibility of the caller to format the output + foreach ($aErrors as $sClass => $aMessages) + { + echo "

Wrong declaration for class $sClass

\n"; + echo "
    \n"; + $i = 0; + foreach ($aMessages as $sMsg) + { + echo "
  • $sMsg ({$aSugFix[$sClass][$i]})
  • \n"; + $i++; + } + echo "
\n"; + } + echo "

Aborting...

\n"; + echo "
\n"; + exit; + } + } + + public static function DBShowApplyForm($sRepairUrl, $sSQLStatementArgName, $aSQLFixes) + { + if (empty($sRepairUrl)) return; + if (count($aSQLFixes) == 0) return; + + echo "
\n"; + echo " \n"; + echo " \n"; + echo "
\n"; + } + + public static function DBExists() + { + return true; // Not enough rights to query for other DB + // returns true if at least one table exists (taking into account the DB sharing) + // then some tables might be missing, but that is made in DBCheckFormat + // + if (empty(self::$m_sTablePrefix)) + { + return CMDBSource::IsDB(self::$m_sDBName); + } + + // DB sharing + // Check if there is at least one table with the prefix + // + if (!CMDBSource::IsDB(self::$m_sDBName)) + { + return false; + } + CMDBSource::SelectDB(self::$m_sDBName); + foreach (CMDBSource::EnumTables() as $sTable) + { + if (substr($sTable, 0, strlen(self::$m_sTablePrefix)) == self::$m_sTablePrefix) return true; + } + return false; + } + + public static function DBDrop() + { + $bDropEntireDB = true; + + if (!empty(self::$m_sTablePrefix)) + { + // Do drop only tables corresponding to the sub-database (table prefix) + // then possibly drop the DB itself (if no table remain) + foreach (CMDBSource::EnumTables() as $sTable) + { + if (substr($sTable, 0, strlen(self::$m_sTablePrefix)) == self::$m_sTablePrefix) + { + CMDBSource::DropTable($sTable); + } + else + { + // There is at least one table which is out of the scope of the current application + $bDropEntireDB = false; + } + } + } + + if ($bDropEntireDB) + { + CMDBSource::DropDB(self::$m_sDBName); + } + } + + + public static function DBCreate() + { + // Note: we have to check if the DB does exist, because we may share the DB + // with other applications (in which case the DB does exist, not the tables with the given prefix) + if (!CMDBSource::IsDB(self::$m_sDBName)) + { + CMDBSource::CreateDB(self::$m_sDBName); + } + self::DBCreateTables(); + } + + protected static function DBCreateTables() + { + list($aErrors, $aSugFix) = self::DBCheckFormat(); + + $aSQL = array(); + foreach ($aSugFix as $sClass => $aQueries) + { + foreach ($aQueries as $sQuery) + { + //$aSQL[] = $sQuery; + // forces a refresh of cached information + CMDBSource::CreateTable($sQuery); + } + } + // does not work -how to have multiple statements in a single query? + // $sDoCreateAll = implode(" ; ", $aSQL); + } + + public static function DBCheckFormat() + { + $aErrors = array(); + $aSugFix = array(); + foreach (self::GetClasses() as $sClass) + { + if (self::IsAbstract($sClass)) continue; + + // Check that the table exists + // + $sTable = self::DBGetTable($sClass); + $sKeyField = self::DBGetKey($sClass); + $sAutoIncrement = (self::IsAutoIncrementKey($sClass) ? "AUTO_INCREMENT" : ""); + if (!CMDBSource::IsTable($sTable)) + { + $aErrors[$sClass][] = "table '$sTable' could not be found into the DB"; + $aSugFix[$sClass][] = "CREATE TABLE `$sTable` (`$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY) ENGINE = innodb"; + } + // Check that the key field exists + // + elseif (!CMDBSource::IsField($sTable, $sKeyField)) + { + $aErrors[$sClass][] = "key '$sKeyField' (table $sTable) could not be found"; + $aSugFix[$sClass][] = "ALTER TABLE `$sTable` ADD `$sKeyField` INT(11) NOT NULL $sAutoIncrement PRIMARY KEY"; + } + else + { + // Check the key field properties + // + if (!CMDBSource::IsKey($sTable, $sKeyField)) + { + $aErrors[$sClass][] = "key '$sKeyField' is not a key for table '$sTable'"; + $aSugFix[$sClass][] = "ALTER TABLE `$sTable`, DROP PRIMARY KEY, ADD PRIMARY key(`$sKeyField`)"; + } + if (self::IsAutoIncrementKey($sClass) && !CMDBSource::IsAutoIncrement($sTable, $sKeyField)) + { + $aErrors[$sClass][] = "key '$sKeyField' (table $sTable) is not automatically incremented"; + $aSugFix[$sClass][] = "ALTER TABLE `$sTable` CHANGE `$sKeyField` `$sKeyField` INT(11) NOT NULL AUTO_INCREMENT"; + } + } + + // Check that any defined field exists + // + $aTableInfo = CMDBSource::GetTableInfo($sTable); + + foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + { + // Skip this attribute if not originaly defined in this class + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; + + foreach($oAttDef->DBGetUsedFields() as $sField) + { + $sDBFieldType = $oAttDef->GetDBFieldType(); + $sFieldSpecs = $oAttDef->IsNullAllowed() ? "$sDBFieldType NULL" : "$sDBFieldType NOT NULL"; + if (!CMDBSource::IsField($sTable, $sField)) + { + $aErrors[$sClass][] = "field '$sField' could not be found in table '$sTable'"; + $aSugFix[$sClass][] = "ALTER TABLE `$sTable` ADD `$sField` $sFieldSpecs"; + } + elseif ($oAttDef->IsNullAllowed() != CMDBSource::IsNullAllowed($sTable, $sField)) + { + if ($oAttDef->IsNullAllowed()) + { + $aErrors[$sClass][] = "field '$sField' in table '$sTable' could be NULL"; + $aSugFix[$sClass][] = "ALTER TABLE `$sTable` CHANGE `$sField` `$sField` $sFieldSpecs"; + } + else + { + $aErrors[$sClass][] = "field '$sField' in table '$sTable' could NOT be NULL"; + $aSugFix[$sClass][] = "ALTER TABLE `$sTable` CHANGE `$sField` `$sField` $sFieldSpecs"; + } + } + } + } + } + return array($aErrors, $aSugFix); + } + + + private static function DBCheckIntegrity_Check2Delete($sSelWrongRecs, $sErrorDesc, $sClass, &$aErrorsAndFixes, &$iNewDelCount, &$aPlannedDel, $bProcessingFriends = false) + { + $sRootClass = self::GetRootClass($sClass); + $sTable = self::DBGetTable($sClass); + $sKeyField = self::DBGetKey($sClass); + + if (array_key_exists($sTable, $aPlannedDel) && count($aPlannedDel[$sTable]) > 0) + { + $sSelWrongRecs .= " AND maintable.`$sKeyField` NOT IN ('".implode("', '", $aPlannedDel[$sTable])."')"; + } + $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "pkey"); + if (count($aWrongRecords) == 0) return; + + if (!array_key_exists($sRootClass, $aErrorsAndFixes)) $aErrorsAndFixes[$sRootClass] = array(); + if (!array_key_exists($sTable, $aErrorsAndFixes[$sRootClass])) $aErrorsAndFixes[$sRootClass][$sTable] = array(); + + foreach ($aWrongRecords as $iRecordId) + { + if (array_key_exists($iRecordId, $aErrorsAndFixes[$sRootClass][$sTable])) + { + switch ($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action']) + { + case 'Delete': + // Already planned for a deletion + // Let's concatenate the errors description together + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] .= ', '.$sErrorDesc; + break; + + case 'Update': + // Let's plan a deletion + break; + } + } + else + { + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] = $sErrorDesc; + } + + if (!$bProcessingFriends) + { + if (!array_key_exists($sTable, $aPlannedDel) || !in_array($iRecordId, $aPlannedDel[$sTable])) + { + // Something new to be deleted... + $iNewDelCount++; + } + } + + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action'] = 'Delete'; + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] = array(); + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Pass'] = 123; + $aPlannedDel[$sTable][] = $iRecordId; + } + + // Now make sure that we would delete the records of the other tables for that class + // + if (!$bProcessingFriends) + { + $sDeleteKeys = "'".implode("', '", $aWrongRecords)."'"; + foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL) as $sFriendClass) + { + $sFriendTable = self::DBGetTable($sFriendClass); + $sFriendKey = self::DBGetKey($sFriendClass); + + // skip the current table + if ($sFriendTable == $sTable) continue; + + $sFindRelatedRec = "SELECT DISTINCT maintable.`$sFriendKey` AS pkey FROM `$sFriendTable` AS maintable WHERE maintable.`$sFriendKey` IN ($sDeleteKeys)"; + self::DBCheckIntegrity_Check2Delete($sFindRelatedRec, "Cascading deletion of record in friend table `$sTable`", $sFriendClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel, true); + } + } + } + + private static function DBCheckIntegrity_Check2Update($sSelWrongRecs, $sErrorDesc, $sColumn, $sNewValue, $sClass, &$aErrorsAndFixes, &$iNewDelCount, &$aPlannedDel) + { + $sRootClass = self::GetRootClass($sClass); + $sTable = self::DBGetTable($sClass); + $sKeyField = self::DBGetKey($sClass); + + if (array_key_exists($sTable, $aPlannedDel) && count($aPlannedDel[$sTable]) > 0) + { + $sSelWrongRecs .= " AND maintable.`$sKeyField` NOT IN ('".implode("', '", $aPlannedDel[$sTable])."')"; + } + $aWrongRecords = CMDBSource::QueryToCol($sSelWrongRecs, "pkey"); + if (count($aWrongRecords) == 0) return; + + if (!array_key_exists($sRootClass, $aErrorsAndFixes)) $aErrorsAndFixes[$sRootClass] = array(); + if (!array_key_exists($sTable, $aErrorsAndFixes[$sRootClass])) $aErrorsAndFixes[$sRootClass][$sTable] = array(); + + foreach ($aWrongRecords as $iRecordId) + { + if (array_key_exists($iRecordId, $aErrorsAndFixes[$sRootClass][$sTable])) + { + switch ($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action']) + { + case 'Delete': + // No need to update, the record will be deleted! + break; + + case 'Update': + // Already planned for an update + // Add this new update spec to the list + $bFoundSameSpec = false; + foreach ($aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] as $aUpdateSpec) + { + if (($sColumn == $aUpdateSpec['column']) && ($sNewValue == $aUpdateSpec['newvalue'])) + { + $bFoundSameSpec = true; + } + } + if (!$bFoundSameSpec) + { + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'][] = (array('column' => $sColumn, 'newvalue'=>$sNewValue)); + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] .= ', '.$sErrorDesc; + } + break; + } + } + else + { + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Reason'] = $sErrorDesc; + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action'] = 'Update'; + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Action_Details'] = array(array('column' => $sColumn, 'newvalue'=>$sNewValue)); + $aErrorsAndFixes[$sRootClass][$sTable][$iRecordId]['Pass'] = 123; + } + + } + } + + // returns the count of records found for deletion + public static function DBCheckIntegrity_SinglePass(&$aErrorsAndFixes, &$iNewDelCount, &$aPlannedDel) + { + foreach (self::GetClasses() as $sClass) + { + if (self::IsAbstract($sClass)) continue; + $sRootClass = self::GetRootClass($sClass); + $sTable = self::DBGetTable($sClass); + $sKeyField = self::DBGetKey($sClass); + + // Check that the final class field contains the name of a class which inherited from the current class + // + if (self::HasFinalClassField($sClass)) + { + $sFinalClassField = self::DBGetClassField($sClass); + + $aAllowedValues = self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); + $sAllowedValues = implode(",", CMDBSource::Quote($aAllowedValues, true)); + + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS pkey FROM `$sTable` AS maintable WHERE `$sFinalClassField` NOT IN ($sAllowedValues)"; + self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "final class (field `$sFinalClassField`) is wrong (expected a value in {".$sAllowedValues."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + + // Compound objects model - node/leaf classes (not the root itself) + // + if (!self::IsStandaloneClass($sClass) && !self::HasFinalClassField($sClass)) + { + $sRootTable = self::DBGetTable($sRootClass); + $sRootKey = self::DBGetKey($sRootClass); + $sFinalClassField = self::DBGetClassField($sRootClass); + + $aExpectedClasses = self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); + $sExpectedClasses = implode(",", CMDBSource::Quote($aExpectedClasses, true)); + + // Check that any record found here has its counterpart in the root table + // and which refers to a child class + // + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS pkey FROM `$sTable` as maintable LEFT JOIN `$sRootTable` ON maintable.`$sKeyField` = `$sRootTable`.`$sRootKey` AND `$sRootTable`.`$sFinalClassField` IN ($sExpectedClasses) WHERE `$sRootTable`.`$sRootKey` IS NULL"; + self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Found a record in `$sTable`, but no counterpart in root table `$sRootTable` (inc. records pointing to a class in {".$sExpectedClasses."})", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + + // Check that any record found in the root table and referring to a child class + // has its counterpart here (detect orphan nodes -root or in the middle of the hierarchy) + // + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sRootKey` AS pkey FROM `$sRootTable` AS maintable LEFT JOIN `$sTable` ON maintable.`$sRootKey` = `$sTable`.`$sKeyField` WHERE `$sTable`.`$sKeyField` IS NULL AND maintable.`$sFinalClassField` IN ($sExpectedClasses)"; + self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Found a record in root table `$sRootTable`, but no counterpart in table `$sTable` (root records pointing to a class in {".$sExpectedClasses."})", $sRootClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + + foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + { + // Skip this attribute if not defined in this table + if (self::$m_aAttribOrigins[$sClass][$sAttCode] != $sClass) continue; + + if ($oAttDef->IsExternalKey()) + { + // Check that any external field is pointing to an existing object + // + $sRemoteClass = $oAttDef->GetTargetClass(); + $sRemoteTable = self::DBGetTable($sRemoteClass); + $sRemoteKey = self::DBGetKey($sRemoteClass); + + $sExtKeyField = $oAttDef->GetSQLExpr(); + + // Note: a class/table may have an external key on itself + $sSelBase = "SELECT DISTINCT maintable.`$sKeyField` AS pkey, maintable.`$sExtKeyField` AS extkey FROM `$sTable` AS maintable LEFT JOIN `$sRemoteTable` ON maintable.`$sExtKeyField` = `$sRemoteTable`.`$sRemoteKey`"; + + $sSelWrongRecs = $sSelBase." WHERE `$sRemoteTable`.`$sRemoteKey` IS NULL"; + if ($oAttDef->IsNullAllowed()) + { + // Exclude the records pointing to 0/null from the errors + $sSelWrongRecs .= " AND maintable.`$sExtKeyField` IS NOT NULL"; + $sSelWrongRecs .= " AND maintable.`$sExtKeyField` != 0"; + self::DBCheckIntegrity_Check2Update($sSelWrongRecs, "Record pointing to (external key '$sAttCode') non existing objects", $sExtKeyField, 'null', $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + else + { + self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Record pointing to (external key '$sAttCode') non existing objects", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + + // Do almost the same, taking into account the records planned for deletion + if (array_key_exists($sRemoteTable, $aPlannedDel) && count($aPlannedDel[$sRemoteTable]) > 0) + { + // This could be done by the mean of a 'OR ... IN (aIgnoreRecords) + // but in that case you won't be able to track the root cause (cascading) + $sSelWrongRecs = $sSelBase." WHERE maintable.`$sExtKeyField` IN ('".implode("', '", $aPlannedDel[$sRemoteTable])."')"; + if ($oAttDef->IsNullAllowed()) + { + // Exclude the records pointing to 0/null from the errors + $sSelWrongRecs .= " AND maintable.`$sExtKeyField` IS NOT NULL"; + $sSelWrongRecs .= " AND maintable.`$sExtKeyField` != 0"; + self::DBCheckIntegrity_Check2Update($sSelWrongRecs, "Record pointing to (external key '$sAttCode') a record planned for deletion", $sExtKeyField, 'null', $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + else + { + self::DBCheckIntegrity_Check2Delete($sSelWrongRecs, "Record pointing to (external key '$sAttCode') a record planned for deletion", $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + } + } + else if ($oAttDef->IsDirectField()) + { + // Check that the values fit the allowed values + // + $aAllowedValues = self::GetAllowedValues_att($sClass, $sAttCode); + if (!is_null($aAllowedValues) && count($aAllowedValues) > 0) + { + $sExpectedValues = implode(",", CMDBSource::Quote(array_keys($aAllowedValues), true)); + + $sMyAttributeField = $oAttDef->GetSQLExpr(); + $sDefaultValue = $oAttDef->GetDefaultValue(); + $sSelWrongRecs = "SELECT DISTINCT maintable.`$sKeyField` AS pkey FROM `$sTable` AS maintable WHERE maintable.`$sMyAttributeField` NOT IN ($sExpectedValues)"; + self::DBCheckIntegrity_Check2Update($sSelWrongRecs, "Record having a column ('$sAttCode') with an unexpected value", $sMyAttributeField, CMDBSource::Quote($sDefaultValue), $sClass, $aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + } + } + } + } + } + + public static function DBCheckIntegrity($sRepairUrl = "", $sSQLStatementArgName = "") + { + // Records in error, and action to be taken: delete or update + // by RootClass/Table/Record + $aErrorsAndFixes = array(); + + // Records to be ignored in the current/next pass + // by Table = array of RecordId + $aPlannedDel = array(); + + // Count of errors in the next pass: no error means that we can leave... + $iErrorCount = 0; + // Limit in case of a bug in the algorythm + $iLoopCount = 0; + + $iNewDelCount = 1; // startup... + while ($iNewDelCount > 0) + { + $iNewDelCount = 0; + self::DBCheckIntegrity_SinglePass($aErrorsAndFixes, $iNewDelCount, $aPlannedDel); + $iErrorCount += $iNewDelCount; + + // Safety net #1 - limit the planned deletions + // + $iMaxDel = 1000; + $iPlannedDel = 0; + foreach ($aPlannedDel as $sTable => $aPlannedDelOnTable) + { + $iPlannedDel += count($aPlannedDelOnTable); + } + if ($iPlannedDel > $iMaxDel) + { + trigger_error("DB Integrity Check safety net - Exceeding the limit of $iMaxDel planned record deletion", E_USER_WARNING); + break; + } + // Safety net #2 - limit the iterations + // + $iLoopCount++; + $iMaxLoops = 10; + if ($iLoopCount > $iMaxLoops) + { + trigger_error("DB Integrity Check safety net - Reached the limit of $iMaxLoops loops", E_USER_WARNING); + break; + } + } + + // Display the results + // + $iIssueCount = 0; + $aFixesDelete = array(); + $aFixesUpdate = array(); + + foreach ($aErrorsAndFixes as $sRootClass => $aTables) + { + foreach ($aTables as $sTable => $aRecords) + { + foreach ($aRecords as $iRecord => $aError) + { + $sAction = $aError['Action']; + $sReason = $aError['Reason']; + $iPass = $aError['Pass']; + + switch ($sAction) + { + case 'Delete': + $sActionDetails = ""; + $aFixesDelete[$sTable][] = $iRecord; + break; + + case 'Update': + $aUpdateDesc = array(); + foreach($aError['Action_Details'] as $aUpdateSpec) + { + $aUpdateDesc[] = $aUpdateSpec['column']." -> ".$aUpdateSpec['newvalue']; + $aFixesUpdate[$sTable][$aUpdateSpec['column']][$aUpdateSpec['newvalue']][] = $iRecord; + } + $sActionDetails = "Set ".implode(", ", $aUpdateDesc); + + break; + + default: + $sActionDetails = "bug: unknown action '$sAction'"; + } + $aIssues[] = "$sRootClass / $sTable / $iRecord / $sReason / $sAction / $sActionDetails"; + $iIssueCount++; + } + } + } + + if ($iIssueCount > 0) + { + // Build the queries to fix in the database + // + // First step, be able to get class data out of the table name + // Could be optimized, because we've made the job earlier... but few benefits, so... + $aTable2ClassProp = array(); + foreach (self::GetClasses() as $sClass) + { + if (self::IsAbstract($sClass)) continue; + + $sRootClass = self::GetRootClass($sClass); + $sTable = self::DBGetTable($sClass); + $sKeyField = self::DBGetKey($sClass); + + $aErrorsAndFixes[$sRootClass][$sTable] = array(); + $aTable2ClassProp[$sTable] = array('rootclass'=>$sRootClass, 'class'=>$sClass, 'keyfield'=>$sKeyField); + } + // Second step, build a flat list of SQL queries + $aSQLFixes = array(); + $iPlannedUpdate = 0; + foreach ($aFixesUpdate as $sTable => $aColumns) + { + foreach ($aColumns as $sColumn => $aNewValues) + { + foreach ($aNewValues as $sNewValue => $aRecords) + { + $iPlannedUpdate += count($aRecords); + $sWrongRecords = "'".implode("', '", $aRecords)."'"; + $sKeyField = $aTable2ClassProp[$sTable]['keyfield']; + + $aSQLFixes[] = "UPDATE `$sTable` SET `$sColumn` = $sNewValue WHERE `$sKeyField` IN ($sWrongRecords)"; + } + } + } + $iPlannedDel = 0; + foreach ($aFixesDelete as $sTable => $aRecords) + { + $iPlannedDel += count($aRecords); + $sWrongRecords = "'".implode("', '", $aRecords)."'"; + $sKeyField = $aTable2ClassProp[$sTable]['keyfield']; + + $aSQLFixes[] = "DELETE FROM `$sTable` WHERE `$sKeyField` IN ($sWrongRecords)"; + } + + // Report the results + // + echo "
"; + echo "

Database corruption error(s): $iErrorCount issues have been encountered. $iPlannedDel records will be deleted, $iPlannedUpdate records will be updated:

\n"; + // #@# later -> this is the responsibility of the caller to format the output + echo "
    \n"; + foreach ($aIssues as $sIssueDesc) + { + echo "
  • $sIssueDesc
  • \n"; + } + echo "
\n"; + self::DBShowApplyForm($sRepairUrl, $sSQLStatementArgName, $aSQLFixes); + echo "

Aborting...

\n"; + echo "
\n"; + exit; + } + } + + public static function Startup($sConfigFile, $bAllowMissingDB = false) + { + self::LoadConfig($sConfigFile); + if (self::DBExists()) + { + CMDBSource::SelectDB(self::$m_sDBName); + } + else + { + if (!$bAllowMissingDB) + { + throw new CoreException('Database not found, check your configuration file', array('config_file'=>$sConfigFile, 'db_name'=>self::$m_sDBName)); + } + } + } + + public static function LoadConfig($sConfigFile) + { + $oConfig = new Config($sConfigFile); + + foreach ($oConfig->GetAppModules() as $sModule => $sToInclude) + { + self::Plugin($sConfigFile, 'application', $sToInclude); + } + foreach ($oConfig->GetDataModels() as $sModule => $sToInclude) + { + self::Plugin($sConfigFile, 'business', $sToInclude); + } + foreach ($oConfig->GetAddons() as $sModule => $sToInclude) + { + self::Plugin($sConfigFile, 'addons', $sToInclude); + } + + $sServer = $oConfig->GetDBHost(); + $sUser = $oConfig->GetDBUser(); + $sPwd = $oConfig->GetDBPwd(); + $sSource = $oConfig->GetDBName(); + $sTablePrefix = $oConfig->GetDBSubname(); + + // The include have been included, let's browse the existing classes and + // develop some data based on the proposed model + self::InitClasses($sTablePrefix); + + self::$m_sDBName = $sSource; + self::$m_sTablePrefix = $sTablePrefix; + + CMDBSource::Init($sServer, $sUser, $sPwd); // do not select the DB (could not exist) + } + + protected static function Plugin($sConfigFile, $sModuleType, $sToInclude) + { + if (!file_exists($sToInclude)) + { + throw new CoreException('Wrong filename in configuration file', array('file' => $sConfigFile, 'module' => $sModuleType, 'filename' => $sToInclude)); + } + require_once($sToInclude); + } + + // Building an object + // + // + + public static function MakeSingleRow($sClass, $iKey) + { + $oFilter = new DBObjectSearch($sClass); + $oFilter->AddCondition('pkey', $iKey, '='); + + $sSQL = self::MakeSelectQuery($oFilter); + //echo "$sSQL
\n"; + $res = CMDBSource::Query($sSQL); + + $aRow = CMDBSource::FetchArray($res); + CMDBSource::FreeResult($res); + if (empty($aRow)) + { + trigger_error("No result for the single row query: '$sSQL'"); + } + return $aRow; + } + + public static function GetObjectByRow($sClass, $aRow) + { + self::_check_subclass($sClass); + + // Compound objects: if available, get the final object class + // + if (!array_key_exists("finalclass", $aRow)) + { + // Either this is a bug (forgot to specify a root class with a finalclass field + // Or this is the expected behavior, because the object is not made of several tables + } + elseif (empty($aRow["finalclass"])) + { + // The data is missing in the DB + // @#@ possible improvement: check that the class is valid ! + $sRootClass = self::GetRootClass($sClass); + $sFinalClassField = self::DBGetClassField($sRootClass); + trigger_error("Empty class name for object $sClass::{$aRow["pkey"]} (root class '$sRootClass', field '{$sFinalClassField}' is empty)", E_USER_ERROR); + } + else + { + // do the job for the real target class + $sClass = $aRow["finalclass"]; + } + return new $sClass($aRow); + } + + public static function GetObject($sClass, $iKey) + { + self::_check_subclass($sClass); + $aRow = self::MakeSingleRow($sClass, $iKey); + if (empty($aRow)) + { + // #@# exception ? + return null; + } + return self::GetObjectByRow($sClass, $aRow); + } + + public static function NewObject($sClass) + { + self::_check_subclass($sClass); + return new $sClass(); + } + + public static function BulkDelete(DBObjectSearch $oFilter) + { + $sSQL = self::MakeDeleteQuery($oFilter); + CMDBSource::Query($sSQL); + } + + public static function BulkUpdate(DBObjectSearch $oFilter, array $aValues) + { + // $aValues is an array of $sAttCode => $value + $sSQL = self::MakeUpdateQuery($oFilter, $aValues); + CMDBSource::Query($sSQL); + } + + // Links + // + // + public static function EnumReferencedClasses($sClass) + { + self::_check_subclass($sClass); + + // 1-N links (referenced by my class), returns an array of sAttCode=>sClass + $aResult = array(); + foreach(self::$m_aAttribDefs[$sClass] as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsExternalKey()) + { + $aResult[$sAttCode] = $oAttDef->GetTargetClass(); + } + } + return $aResult; + } + public static function EnumReferencingClasses($sClass, $bSkipLinkingClasses = false) + { + self::_check_subclass($sClass); + + $aLinksClasses = self::EnumLinksClasses(); + + // 1-N links (referencing my class), array of sClass => array of sAttcode + $aResult = array(); + foreach (self::$m_aAttribDefs as $sSomeClass=>$aClassAttributes) + { + if ($bSkipLinkingClasses && in_array($sSomeClass, $aLinksClasses)) continue; + + $aExtKeys = array(); + foreach ($aClassAttributes as $sAttCode=>$oAttDef) + { + if (self::$m_aAttribOrigins[$sSomeClass][$sAttCode] != $sSomeClass) continue; + if ($oAttDef->IsExternalKey() && ($oAttDef->GetTargetClass() == $sClass)) + { + $aExtKeys[] = $sAttCode; + } + } + if (count($aExtKeys) != 0) + { + $aResult[$sSomeClass] = $aExtKeys; + } + } + return $aResult; + } + public static function EnumLinksClasses() + { + // Returns a flat array of classes having at least two external keys + $aResult = array(); + foreach (self::$m_aAttribDefs as $sSomeClass=>$aClassAttributes) + { + $iExtKeyCount = 0; + foreach ($aClassAttributes as $sAttCode=>$oAttDef) + { + if (self::$m_aAttribOrigins[$sSomeClass][$sAttCode] != $sSomeClass) continue; + if ($oAttDef->IsExternalKey()) + { + $iExtKeyCount++; + } + } + if ($iExtKeyCount >= 2) + { + $aResult[] = $sSomeClass; + } + } + return $aResult; + } + public static function EnumLinkingClasses($sClass = "") + { + // N-N links, array of sLinkClass => (array of sAttCode=>sClass) + $aResult = array(); + foreach (self::EnumLinksClasses() as $sSomeClass) + { + $aTargets = array(); + $bFoundClass = false; + foreach (self::ListAttributeDefs($sSomeClass) as $sAttCode=>$oAttDef) + { + if (self::$m_aAttribOrigins[$sSomeClass][$sAttCode] != $sSomeClass) continue; + if ($oAttDef->IsExternalKey()) + { + $sRemoteClass = $oAttDef->GetTargetClass(); + if (empty($sClass)) + { + $aTargets[$sAttCode] = $sRemoteClass; + } + elseif ($sClass == $sRemoteClass) + { + $bFoundClass = true; + } + else + { + $aTargets[$sAttCode] = $sRemoteClass; + } + } + } + if (empty($sClass) || $bFoundClass) + { + $aResult[$sSomeClass] = $aTargets; + } + } + return $aResult; + } + + public static function GetLinkLabel($sLinkClass, $sAttCode) + { + self::_check_subclass($sLinkClass); + + // e.g. "supported by" (later: $this->GetLinkLabel(), computed on link data!) + return self::GetLabel($sLinkClass, $sAttCode); + } + + // To be overloaded + protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields) + { + $sLabel = htmlentities(implode(' / ', $aAvailableFields)); + $sHint = htmlentities("$sObjClass::$sObjKey"); + return "$sLabel"; + } + +} // class MetaModel + + +// Standard attribute lists +MetaModel::RegisterZList("noneditable", array("description"=>"non editable fields", "type"=>"attributes")); + +MetaModel::RegisterZList("details", array("description"=>"All attributes to be displayed for the 'details' of an object", "type"=>"attributes")); +MetaModel::RegisterZList("list", array("description"=>"All attributes to be displayed for a list of objects", "type"=>"attributes")); +MetaModel::RegisterZList("preview", array("description"=>"All attributes visible in preview mode", "type"=>"attributes")); + +MetaModel::RegisterZList("standard_search", array("description"=>"List of criteria for the standard search", "type"=>"filters")); +MetaModel::RegisterZList("advanced_search", array("description"=>"List of criteria for the advanced search", "type"=>"filters")); + + +?> diff --git a/core/oql/build.cmd b/core/oql/build.cmd new file mode 100644 index 000000000..2187cec66 --- /dev/null +++ b/core/oql/build.cmd @@ -0,0 +1,3 @@ +c:\itop\php-5.2.3\php.exe -q "C:\itop\PHP-5.2.3\PEAR\PHP\LexerGenerator\cli.php" oql-lexer.plex +c:\itop\php-5.2.3\php.exe -q "C:\itop\PHP-5.2.3\PEAR\PHP\ParserGenerator\cli.php" oql-parser.y +pause \ No newline at end of file diff --git a/core/oql/oql-lexer.php b/core/oql/oql-lexer.php new file mode 100644 index 000000000..dede6ca1f --- /dev/null +++ b/core/oql/oql-lexer.php @@ -0,0 +1,522 @@ +data = $data; + $this->count = 0; + $this->line = 1; + } + + + private $_yy_state = 1; + private $_yy_stack = array(); + + function yylex() + { + return $this->{'yylex' . $this->_yy_state}(); + } + + function yypushstate($state) + { + array_push($this->_yy_stack, $this->_yy_state); + $this->_yy_state = $state; + } + + function yypopstate() + { + $this->_yy_state = array_pop($this->_yy_stack); + } + + function yybegin($state) + { + $this->_yy_state = $state; + } + + + + + function yylex1() + { + if ($this->count >= strlen($this->data)) { + return false; // end of input + } + do { + $rules = array( + '/^[ \t\n]+/', + '/^SELECT/', + '/^AS/', + '/^WHERE/', + '/^JOIN/', + '/^ON/', + '/^\//', + '/^\\*/', + '/^\\+/', + '/^-/', + '/^AND/', + '/^OR/', + '/^,/', + '/^\\(/', + '/^\\)/', + '/^=/', + '/^!=/', + '/^>/', + '/^=/', + '/^<=/', + '/^LIKE/', + '/^NOT LIKE/', + '/^IN/', + '/^NOT IN/', + '/^INTERVAL/', + '/^IF/', + '/^ELT/', + '/^COALESCE/', + '/^CONCAT/', + '/^SUBSTR/', + '/^TRIM/', + '/^DATE/', + '/^DATE_FORMAT/', + '/^CURRENT_DATE/', + '/^NOW/', + '/^TIME/', + '/^TO_DAYS/', + '/^FROM_DAYS/', + '/^YEAR/', + '/^MONTH/', + '/^DAY/', + '/^DATE_ADD/', + '/^DATE_SUB/', + '/^ROUND/', + '/^FLOOR/', + '/^[0-9]+|0x[0-9a-fA-F]+/', + '/^\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/', + '/^([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/', + '/^\\./', + ); + $match = false; + foreach ($rules as $index => $rule) { + if (preg_match($rule, substr($this->data, $this->count), $yymatches)) { + if ($match) { + if (strlen($yymatches[0]) > strlen($match[0][0])) { + $match = array($yymatches, $index); // matches, token + } + } else { + $match = array($yymatches, $index); + } + } + } + if (!$match) { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->count]); + } + $this->token = $match[1]; + $this->value = $match[0][0]; + $yysubmatches = $match[0]; + array_shift($yysubmatches); + if (!$yysubmatches) { + $yysubmatches = array(); + } + $r = $this->{'yy_r1_' . $this->token}($yysubmatches); + if ($r === null) { + $this->count += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + // accept this token + return true; + } elseif ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } elseif ($r === false) { + $this->count += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + if ($this->count >= strlen($this->data)) { + return false; // end of input + } + // skip this token + continue; + } else { + $yy_yymore_patterns = array_slice($rules, $this->token, true); + // yymore is needed + do { + if (!isset($yy_yymore_patterns[$this->token])) { + throw new Exception('cannot do yymore for the last token'); + } + $match = false; + foreach ($yy_yymore_patterns[$this->token] as $index => $rule) { + if (preg_match('/' . $rule . '/', + substr($this->data, $this->count), $yymatches)) { + $yymatches = array_filter($yymatches, 'strlen'); // remove empty sub-patterns + if ($match) { + if (strlen($yymatches[0]) > strlen($match[0][0])) { + $match = array($yymatches, $index); // matches, token + } + } else { + $match = array($yymatches, $index); + } + } + } + if (!$match) { + throw new Exception('Unexpected input at line' . $this->line . + ': ' . $this->data[$this->count]); + } + $this->token = $match[1]; + $this->value = $match[0][0]; + $yysubmatches = $match[0]; + array_shift($yysubmatches); + if (!$yysubmatches) { + $yysubmatches = array(); + } + $this->line = substr_count($this->value, "\n"); + $r = $this->{'yy_r1_' . $this->token}(); + } while ($r !== null || !$r); + if ($r === true) { + // we have changed state + // process this token in the new state + return $this->yylex(); + } else { + // accept + $this->count += strlen($this->value); + $this->line += substr_count($this->value, "\n"); + return true; + } + } + } while (true); + + } // end function + + function yy_r1_0($yy_subpatterns) + { + + return false; + } + function yy_r1_1($yy_subpatterns) + { + + $this->token = OQLParser::SELECT; + } + function yy_r1_2($yy_subpatterns) + { + + $this->token = OQLParser::AS_ALIAS; + } + function yy_r1_3($yy_subpatterns) + { + + $this->token = OQLParser::WHERE; + } + function yy_r1_4($yy_subpatterns) + { + + $this->token = OQLParser::JOIN; + } + function yy_r1_5($yy_subpatterns) + { + + $this->token = OQLParser::ON; + } + function yy_r1_6($yy_subpatterns) + { + + $this->token = OQLParser::MATH_DIV; + } + function yy_r1_7($yy_subpatterns) + { + + $this->token = OQLParser::MATH_MULT; + } + function yy_r1_8($yy_subpatterns) + { + + $this->token = OQLParser::MATH_PLUS; + } + function yy_r1_9($yy_subpatterns) + { + + $this->token = OQLParser::MATH_MINUS; + } + function yy_r1_10($yy_subpatterns) + { + + $this->token = OQLParser::LOG_AND; + } + function yy_r1_11($yy_subpatterns) + { + + $this->token = OQLParser::LOG_OR; + } + function yy_r1_12($yy_subpatterns) + { + + $this->token = OQLParser::COMA; + } + function yy_r1_13($yy_subpatterns) + { + + $this->token = OQLParser::PAR_OPEN; + } + function yy_r1_14($yy_subpatterns) + { + + $this->token = OQLParser::PAR_CLOSE; + } + function yy_r1_15($yy_subpatterns) + { + + $this->token = OQLParser::EQ; + } + function yy_r1_16($yy_subpatterns) + { + + $this->token = OQLParser::NOT_EQ; + } + function yy_r1_17($yy_subpatterns) + { + + $this->token = OQLParser::GT; + } + function yy_r1_18($yy_subpatterns) + { + + $this->token = OQLParser::LT; + } + function yy_r1_19($yy_subpatterns) + { + + $this->token = OQLParser::GE; + } + function yy_r1_20($yy_subpatterns) + { + + $this->token = OQLParser::LE; + } + function yy_r1_21($yy_subpatterns) + { + + $this->token = OQLParser::LIKE; + } + function yy_r1_22($yy_subpatterns) + { + + $this->token = OQLParser::NOT_LIKE; + } + function yy_r1_23($yy_subpatterns) + { + + $this->token = OQLParser::IN; + } + function yy_r1_24($yy_subpatterns) + { + + $this->token = OQLParser::NOT_IN; + } + function yy_r1_25($yy_subpatterns) + { + + $this->token = OQLParser::INTERVAL; + } + function yy_r1_26($yy_subpatterns) + { + + $this->token = OQLParser::F_IF; + } + function yy_r1_27($yy_subpatterns) + { + + $this->token = OQLParser::F_ELT; + } + function yy_r1_28($yy_subpatterns) + { + + $this->token = OQLParser::F_COALESCE; + } + function yy_r1_29($yy_subpatterns) + { + + $this->token = OQLParser::F_CONCAT; + } + function yy_r1_30($yy_subpatterns) + { + + $this->token = OQLParser::F_SUBSTR; + } + function yy_r1_31($yy_subpatterns) + { + + $this->token = OQLParser::F_TRIM; + } + function yy_r1_32($yy_subpatterns) + { + + $this->token = OQLParser::F_DATE; + } + function yy_r1_33($yy_subpatterns) + { + + $this->token = OQLParser::F_DATE_FORMAT; + } + function yy_r1_34($yy_subpatterns) + { + + $this->token = OQLParser::F_CURRENT_DATE; + } + function yy_r1_35($yy_subpatterns) + { + + $this->token = OQLParser::F_NOW; + } + function yy_r1_36($yy_subpatterns) + { + + $this->token = OQLParser::F_TIME; + } + function yy_r1_37($yy_subpatterns) + { + + $this->token = OQLParser::F_TO_DAYS; + } + function yy_r1_38($yy_subpatterns) + { + + $this->token = OQLParser::F_FROM_DAYS; + } + function yy_r1_39($yy_subpatterns) + { + + $this->token = OQLParser::F_YEAR; + } + function yy_r1_40($yy_subpatterns) + { + + $this->token = OQLParser::F_MONTH; + } + function yy_r1_41($yy_subpatterns) + { + + $this->token = OQLParser::F_DAY; + } + function yy_r1_42($yy_subpatterns) + { + + $this->token = OQLParser::F_DATE_ADD; + } + function yy_r1_43($yy_subpatterns) + { + + $this->token = OQLParser::F_DATE_SUB; + } + function yy_r1_44($yy_subpatterns) + { + + $this->token = OQLParser::F_ROUND; + } + function yy_r1_45($yy_subpatterns) + { + + $this->token = OQLParser::F_FLOOR; + } + function yy_r1_46($yy_subpatterns) + { + + $this->token = OQLParser::NUMVAL; + } + function yy_r1_47($yy_subpatterns) + { + + $this->token = OQLParser::STRVAL; + } + function yy_r1_48($yy_subpatterns) + { + + $this->token = OQLParser::NAME; + } + function yy_r1_49($yy_subpatterns) + { + + $this->token = OQLParser::DOT; + } + + +} + +define('UNEXPECTED_INPUT_AT_LINE', 'Unexpected input at line'); + +class OQLLexerException extends OQLException +{ + public function __construct($sInput, $iLine, $iCol, $sUnexpected) + { + parent::__construct("Syntax error", $sInput, $iLine, $iCol, $sUnexpected); + } +} + +class OQLLexer extends OQLLexerRaw +{ + public function getTokenPos() + { + return max(0, $this->count - strlen($this->value)); + } + + 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; + } + } +} +?> diff --git a/core/oql/oql-lexer.plex b/core/oql/oql-lexer.plex new file mode 100644 index 000000000..8196f540a --- /dev/null +++ b/core/oql/oql-lexer.plex @@ -0,0 +1,305 @@ +data = $data; + $this->count = 0; + $this->line = 1; + } + +/*!lex2php +%input $this->data +%counter $this->count +%token $this->token +%value $this->value +%line $this->line +%matchlongest 1 +whitespace = /[ \t\n]+/ +select = "SELECT" +as_alias = "AS" +where = "WHERE" +join = "JOIN" +on = "ON" +coma = "," +par_open = "(" +par_close = ")" +math_div = "/" +math_mult = "*" +math_plus = "+" +math_minus = "-" +log_and = "AND" +log_or = "OR" +eq = "=" +not_eq = "!=" +gt = ">" +lt = "<" +ge = ">=" +le = "<=" +like = "LIKE" +not_like = "NOT LIKE" +in = "IN" +not_in = "NOT IN" +interval = "INTERVAL" +f_if = "IF" +f_elt = "ELT" +f_coalesce = "COALESCE" +f_concat = "CONCAT" +f_substr = "SUBSTR" +f_trim = "TRIM" +f_date = "DATE" +f_date_format = "DATE_FORMAT" +f_current_date = "CURRENT_DATE" +f_now = "NOW" +f_time = "TIME" +f_to_days = "TO_DAYS" +f_from_days = "FROM_DAYS" +f_year = "YEAR" +f_month = "MONTH" +f_day = "DAY" +f_date_add = "DATE_ADD" +f_date_sub = "DATE_SUB" +f_round = "ROUND" +f_floor = "FLOOR" +numval = /[0-9]+|0x[0-9a-fA-F]+/ +strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/ +name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ +dot = "." +*/ + +/*!lex2php +whitespace { + return false; +} +select { + $this->token = OQLParser::SELECT; +} +as_alias { + $this->token = OQLParser::AS_ALIAS; +} +where { + $this->token = OQLParser::WHERE; +} +join { + $this->token = OQLParser::JOIN; +} +on { + $this->token = OQLParser::ON; +} +math_div { + $this->token = OQLParser::MATH_DIV; +} +math_mult { + $this->token = OQLParser::MATH_MULT; +} +math_plus { + $this->token = OQLParser::MATH_PLUS; +} +math_minus { + $this->token = OQLParser::MATH_MINUS; +} +log_and { + $this->token = OQLParser::LOG_AND; +} +log_or { + $this->token = OQLParser::LOG_OR; +} +coma { + $this->token = OQLParser::COMA; +} +par_open { + $this->token = OQLParser::PAR_OPEN; +} +par_close { + $this->token = OQLParser::PAR_CLOSE; +} +eq { + $this->token = OQLParser::EQ; +} +not_eq { + $this->token = OQLParser::NOT_EQ; +} +gt { + $this->token = OQLParser::GT; +} +lt { + $this->token = OQLParser::LT; +} +ge { + $this->token = OQLParser::GE; +} +le { + $this->token = OQLParser::LE; +} +like { + $this->token = OQLParser::LIKE; +} +not_like { + $this->token = OQLParser::NOT_LIKE; +} +in { + $this->token = OQLParser::IN; +} +not_in { + $this->token = OQLParser::NOT_IN; +} +interval { + $this->token = OQLParser::INTERVAL; +} +f_if { + $this->token = OQLParser::F_IF; +} +f_elt { + $this->token = OQLParser::F_ELT; +} +f_coalesce { + $this->token = OQLParser::F_COALESCE; +} +f_concat { + $this->token = OQLParser::F_CONCAT; +} +f_substr { + $this->token = OQLParser::F_SUBSTR; +} +f_trim { + $this->token = OQLParser::F_TRIM; +} +f_date { + $this->token = OQLParser::F_DATE; +} +f_date_format { + $this->token = OQLParser::F_DATE_FORMAT; +} +f_current_date { + $this->token = OQLParser::F_CURRENT_DATE; +} +f_now { + $this->token = OQLParser::F_NOW; +} +f_time { + $this->token = OQLParser::F_TIME; +} +f_to_days { + $this->token = OQLParser::F_TO_DAYS; +} +f_from_days { + $this->token = OQLParser::F_FROM_DAYS; +} +f_year { + $this->token = OQLParser::F_YEAR; +} +f_month { + $this->token = OQLParser::F_MONTH; +} +f_day { + $this->token = OQLParser::F_DAY; +} +f_date_add { + $this->token = OQLParser::F_DATE_ADD; +} +f_date_sub { + $this->token = OQLParser::F_DATE_SUB; +} +f_round { + $this->token = OQLParser::F_ROUND; +} +f_floor { + $this->token = OQLParser::F_FLOOR; +} +numval { + $this->token = OQLParser::NUMVAL; +} +strval { + $this->token = OQLParser::STRVAL; +} +name { + $this->token = OQLParser::NAME; +} +dot { + $this->token = OQLParser::DOT; +} +*/ + +} + +define('UNEXPECTED_INPUT_AT_LINE', 'Unexpected input at line'); + +class OQLLexerException extends OQLException +{ + public function __construct($sInput, $iLine, $iCol, $sUnexpected) + { + parent::__construct("Syntax error", $sInput, $iLine, $iCol, $sUnexpected); + } +} + +class OQLLexer extends OQLLexerRaw +{ + public function getTokenPos() + { + return max(0, $this->count - strlen($this->value)); + } + + 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; + } + } +} +?> diff --git a/core/oql/oql-parser.php b/core/oql/oql-parser.php new file mode 100644 index 000000000..faf64faee --- /dev/null +++ b/core/oql/oql-parser.php @@ -0,0 +1,1613 @@ +string = $s->string; + $this->metadata = $s->metadata; + } else { + $this->string = (string) $s; + if ($m instanceof OQLParser_yyToken) { + $this->metadata = $m->metadata; + } elseif (is_array($m)) { + $this->metadata = $m; + } + } + } + + function __toString() + { + return $this->_string; + } + + function offsetExists($offset) + { + return isset($this->metadata[$offset]); + } + + function offsetGet($offset) + { + return $this->metadata[$offset]; + } + + function offsetSet($offset, $value) + { + if ($offset === null) { + if (isset($value[0])) { + $x = ($value instanceof OQLParser_yyToken) ? + $value->metadata : $value; + $this->metadata = array_merge($this->metadata, $x); + return; + } + $offset = count($this->metadata); + } + if ($value === null) { + return; + } + if ($value instanceof OQLParser_yyToken) { + if ($value->metadata) { + $this->metadata[$offset] = $value->metadata; + } + } elseif ($value) { + $this->metadata[$offset] = $value; + } + } + + function offsetUnset($offset) + { + unset($this->metadata[$offset]); + } +} + +/** The following structure represents a single element of the + * parser's stack. Information stored includes: + * + * + The state number for the parser at this level of the stack. + * + * + The value of the token stored at this level of the stack. + * (In other words, the "major" token.) + * + * + The semantic value stored at this level of the stack. This is + * the information used by the action routines in the grammar. + * It is sometimes called the "minor" token. + */ +class OQLParser_yyStackEntry +{ + public $stateno; /* The state-number */ + public $major; /* The major token value. This is the code + ** number for the token at this stack level */ + public $minor; /* The user-supplied minor token value. This + ** is the value of the token */ +}; + +// code external to the class is included here + +// declare_class is output here +#line 2 "oql-parser.y" +class OQLParserRaw#line 102 "oql-parser.php" +{ +/* First off, code is included which follows the "include_class" declaration +** in the input file. */ + +/* Next is all token values, as class constants +*/ +/* +** These constants (all generated automatically by the parser generator) +** specify the various kinds of tokens (terminals) that the parser +** understands. +** +** Each symbol here is a terminal symbol in the grammar. +*/ + const SELECT = 1; + const AS_ALIAS = 2; + const WHERE = 3; + const JOIN = 4; + const ON = 5; + const EQ = 6; + const PAR_OPEN = 7; + const PAR_CLOSE = 8; + const COMA = 9; + const INTERVAL = 10; + const F_DAY = 11; + const F_MONTH = 12; + const F_YEAR = 13; + const DOT = 14; + const NAME = 15; + const NUMVAL = 16; + const STRVAL = 17; + const NOT_EQ = 18; + const LOG_AND = 19; + const LOG_OR = 20; + const GT = 21; + const LT = 22; + const GE = 23; + const LE = 24; + const MATH_DIV = 25; + const MATH_MULT = 26; + const MATH_PLUS = 27; + const MATH_MINUS = 28; + const LIKE = 29; + const NOT_LIKE = 30; + const IN = 31; + const NOT_IN = 32; + const F_IF = 33; + const F_ELT = 34; + const F_COALESCE = 35; + const F_CONCAT = 36; + const F_SUBSTR = 37; + const F_TRIM = 38; + const F_DATE = 39; + const F_DATE_FORMAT = 40; + const F_CURRENT_DATE = 41; + const F_NOW = 42; + const F_TIME = 43; + const F_TO_DAYS = 44; + const F_FROM_DAYS = 45; + const F_DATE_ADD = 46; + const F_DATE_SUB = 47; + const F_ROUND = 48; + const F_FLOOR = 49; + const YY_NO_ACTION = 186; + const YY_ACCEPT_ACTION = 185; + const YY_ERROR_ACTION = 184; + +/* Next are that tables used to determine what action to take based on the +** current state and lookahead token. These tables are used to implement +** functions that take a state number and lookahead value and return an +** action integer. +** +** Suppose the action integer is N. Then the action is determined as +** follows +** +** 0 <= N < self::YYNSTATE Shift N. That is, +** push the lookahead +** token onto the stack +** and goto state N. +** +** self::YYNSTATE <= N < self::YYNSTATE+self::YYNRULE Reduce by rule N-YYNSTATE. +** +** N == self::YYNSTATE+self::YYNRULE A syntax error has occurred. +** +** N == self::YYNSTATE+self::YYNRULE+1 The parser accepts its +** input. (and concludes parsing) +** +** N == self::YYNSTATE+self::YYNRULE+2 No such action. Denotes unused +** slots in the yy_action[] table. +** +** The action table is constructed as a single large static array $yy_action. +** Given state S and lookahead X, the action is computed as +** +** self::$yy_action[self::$yy_shift_ofst[S] + X ] +** +** If the index value self::$yy_shift_ofst[S]+X is out of range or if the value +** self::$yy_lookahead[self::$yy_shift_ofst[S]+X] is not equal to X or if +** self::$yy_shift_ofst[S] is equal to self::YY_SHIFT_USE_DFLT, it means that +** the action is not in the table and that self::$yy_default[S] should be used instead. +** +** The formula above is for computing the action when the lookahead is +** a terminal symbol. If the lookahead is a non-terminal (as occurs after +** a reduce action) then the static $yy_reduce_ofst array is used in place of +** the static $yy_shift_ofst array and self::YY_REDUCE_USE_DFLT is used in place of +** self::YY_SHIFT_USE_DFLT. +** +** The following are the tables generated in this section: +** +** self::$yy_action A single table containing all actions. +** self::$yy_lookahead A table containing the lookahead for each entry in +** yy_action. Used to detect hash collisions. +** self::$yy_shift_ofst For each state, the offset into self::$yy_action for +** shifting terminals. +** self::$yy_reduce_ofst For each state, the offset into self::$yy_action for +** shifting non-terminals after a reduce. +** self::$yy_default Default action for each state. +*/ + const YY_SZ_ACTTAB = 369; +static public $yy_action = array( + /* 0 */ 6, 67, 66, 5, 61, 62, 60, 65, 35, 67, + /* 10 */ 66, 82, 30, 83, 13, 81, 75, 74, 68, 81, + /* 20 */ 75, 74, 68, 8, 29, 20, 42, 44, 41, 43, + /* 30 */ 36, 37, 38, 39, 63, 58, 57, 56, 59, 55, + /* 40 */ 54, 48, 47, 23, 40, 40, 31, 49, 4, 6, + /* 50 */ 27, 52, 14, 61, 62, 60, 94, 35, 67, 66, + /* 60 */ 64, 2, 69, 70, 73, 22, 40, 50, 15, 18, + /* 70 */ 26, 21, 18, 19, 33, 42, 44, 41, 43, 36, + /* 80 */ 37, 38, 39, 63, 58, 57, 56, 59, 55, 54, + /* 90 */ 48, 47, 6, 4, 40, 27, 61, 62, 60, 3, + /* 100 */ 35, 67, 66, 46, 24, 1, 18, 69, 70, 73, + /* 110 */ 80, 25, 16, 19, 35, 77, 17, 158, 42, 44, + /* 120 */ 41, 43, 36, 37, 38, 39, 63, 58, 57, 56, + /* 130 */ 59, 55, 54, 48, 47, 72, 40, 158, 158, 158, + /* 140 */ 93, 92, 105, 158, 158, 158, 158, 71, 84, 85, + /* 150 */ 99, 98, 97, 100, 101, 104, 103, 102, 96, 95, + /* 160 */ 89, 88, 72, 158, 79, 158, 158, 158, 158, 158, + /* 170 */ 158, 158, 158, 158, 71, 84, 85, 99, 98, 97, + /* 180 */ 100, 101, 104, 103, 102, 96, 95, 89, 88, 72, + /* 190 */ 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, + /* 200 */ 158, 71, 84, 85, 99, 98, 97, 100, 101, 104, + /* 210 */ 103, 102, 96, 95, 89, 88, 185, 90, 78, 31, + /* 220 */ 158, 158, 158, 158, 86, 12, 158, 87, 158, 31, + /* 230 */ 32, 158, 158, 53, 34, 81, 75, 74, 68, 40, + /* 240 */ 31, 158, 158, 158, 158, 86, 11, 158, 87, 40, + /* 250 */ 158, 32, 28, 158, 45, 158, 81, 75, 74, 68, + /* 260 */ 40, 31, 158, 158, 158, 158, 86, 11, 158, 87, + /* 270 */ 158, 158, 32, 158, 158, 91, 158, 81, 75, 74, + /* 280 */ 68, 40, 158, 158, 76, 31, 158, 158, 158, 158, + /* 290 */ 86, 12, 158, 87, 158, 31, 32, 158, 158, 51, + /* 300 */ 34, 81, 75, 74, 68, 40, 31, 158, 158, 158, + /* 310 */ 158, 86, 9, 158, 87, 40, 158, 32, 158, 158, + /* 320 */ 158, 158, 81, 75, 74, 68, 40, 31, 158, 158, + /* 330 */ 158, 158, 86, 10, 158, 87, 158, 158, 32, 158, + /* 340 */ 158, 158, 158, 81, 75, 74, 68, 40, 31, 158, + /* 350 */ 158, 158, 158, 86, 7, 158, 87, 158, 158, 32, + /* 360 */ 158, 158, 158, 158, 81, 75, 74, 68, 40, + ); + static public $yy_lookahead = array( + /* 0 */ 7, 16, 17, 10, 11, 12, 13, 62, 15, 16, + /* 10 */ 17, 62, 67, 8, 9, 70, 71, 72, 73, 70, + /* 20 */ 71, 72, 73, 7, 54, 54, 33, 34, 35, 36, + /* 30 */ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + /* 40 */ 47, 48, 49, 1, 74, 74, 54, 56, 61, 7, + /* 50 */ 63, 59, 5, 11, 12, 13, 69, 15, 16, 17, + /* 60 */ 8, 9, 75, 76, 77, 2, 74, 55, 5, 57, + /* 70 */ 55, 2, 57, 4, 54, 33, 34, 35, 36, 37, + /* 80 */ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + /* 90 */ 48, 49, 7, 61, 74, 63, 11, 12, 13, 3, + /* 100 */ 15, 16, 17, 74, 55, 7, 57, 75, 76, 77, + /* 110 */ 64, 14, 6, 4, 15, 56, 54, 78, 33, 34, + /* 120 */ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + /* 130 */ 45, 46, 47, 48, 49, 6, 74, 78, 78, 78, + /* 140 */ 11, 12, 13, 78, 78, 78, 78, 18, 19, 20, + /* 150 */ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + /* 160 */ 31, 32, 6, 78, 8, 78, 78, 78, 78, 78, + /* 170 */ 78, 78, 78, 78, 18, 19, 20, 21, 22, 23, + /* 180 */ 24, 25, 26, 27, 28, 29, 30, 31, 32, 6, + /* 190 */ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + /* 200 */ 78, 18, 19, 20, 21, 22, 23, 24, 25, 26, + /* 210 */ 27, 28, 29, 30, 31, 32, 51, 52, 53, 54, + /* 220 */ 78, 78, 78, 78, 59, 60, 78, 62, 78, 54, + /* 230 */ 65, 78, 78, 58, 59, 70, 71, 72, 73, 74, + /* 240 */ 54, 78, 78, 78, 78, 59, 60, 78, 62, 74, + /* 250 */ 78, 65, 66, 78, 68, 78, 70, 71, 72, 73, + /* 260 */ 74, 54, 78, 78, 78, 78, 59, 60, 78, 62, + /* 270 */ 78, 78, 65, 78, 78, 68, 78, 70, 71, 72, + /* 280 */ 73, 74, 78, 78, 53, 54, 78, 78, 78, 78, + /* 290 */ 59, 60, 78, 62, 78, 54, 65, 78, 78, 58, + /* 300 */ 59, 70, 71, 72, 73, 74, 54, 78, 78, 78, + /* 310 */ 78, 59, 60, 78, 62, 74, 78, 65, 78, 78, + /* 320 */ 78, 78, 70, 71, 72, 73, 74, 54, 78, 78, + /* 330 */ 78, 78, 59, 60, 78, 62, 78, 78, 65, 78, + /* 340 */ 78, 78, 78, 70, 71, 72, 73, 74, 54, 78, + /* 350 */ 78, 78, 78, 59, 60, 78, 62, 78, 78, 65, + /* 360 */ 78, 78, 78, 78, 70, 71, 72, 73, 74, +); + const YY_SHIFT_USE_DFLT = -16; + const YY_SHIFT_MAX = 34; + static public $yy_shift_ofst = array( + /* 0 */ 42, -7, -7, 85, 85, 85, 85, 129, -15, 156, + /* 10 */ 183, 183, 183, -15, 99, 99, 99, 69, 109, 99, + /* 20 */ 109, 99, 99, 99, 96, 99, 96, 16, 52, 63, + /* 30 */ 5, 97, 98, 47, 106, +); + const YY_REDUCE_USE_DFLT = -56; + const YY_REDUCE_MAX = 27; + static public $yy_reduce_ofst = array( + /* 0 */ 165, 186, 207, 231, 273, 294, 252, -13, -55, 32, + /* 10 */ 32, 32, 32, -51, 175, 241, -8, 49, 12, -30, + /* 20 */ 15, -29, 20, 62, 59, 29, -9, 46, +); + static public $yyExpectedTokens = array( + /* 0 */ array(1, 7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 1 */ array(7, 10, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 2 */ array(7, 10, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 3 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 4 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 5 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 6 */ array(7, 11, 12, 13, 15, 16, 17, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ), + /* 7 */ array(6, 11, 12, 13, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), + /* 8 */ array(16, 17, ), + /* 9 */ array(6, 8, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), + /* 10 */ array(6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), + /* 11 */ array(6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), + /* 12 */ array(6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ), + /* 13 */ array(16, 17, ), + /* 14 */ array(15, ), + /* 15 */ array(15, ), + /* 16 */ array(15, ), + /* 17 */ array(2, 4, ), + /* 18 */ array(4, ), + /* 19 */ array(15, ), + /* 20 */ array(4, ), + /* 21 */ array(15, ), + /* 22 */ array(15, ), + /* 23 */ array(15, ), + /* 24 */ array(3, ), + /* 25 */ array(15, ), + /* 26 */ array(3, ), + /* 27 */ array(7, ), + /* 28 */ array(8, 9, ), + /* 29 */ array(2, 5, ), + /* 30 */ array(8, 9, ), + /* 31 */ array(14, ), + /* 32 */ array(7, ), + /* 33 */ array(5, ), + /* 34 */ array(6, ), + /* 35 */ array(), + /* 36 */ array(), + /* 37 */ array(), + /* 38 */ array(), + /* 39 */ array(), + /* 40 */ array(), + /* 41 */ array(), + /* 42 */ array(), + /* 43 */ array(), + /* 44 */ array(), + /* 45 */ array(), + /* 46 */ array(), + /* 47 */ array(), + /* 48 */ array(), + /* 49 */ array(), + /* 50 */ array(), + /* 51 */ array(), + /* 52 */ array(), + /* 53 */ array(), + /* 54 */ array(), + /* 55 */ array(), + /* 56 */ array(), + /* 57 */ array(), + /* 58 */ array(), + /* 59 */ array(), + /* 60 */ array(), + /* 61 */ array(), + /* 62 */ array(), + /* 63 */ array(), + /* 64 */ array(), + /* 65 */ array(), + /* 66 */ array(), + /* 67 */ array(), + /* 68 */ array(), + /* 69 */ array(), + /* 70 */ array(), + /* 71 */ array(), + /* 72 */ array(), + /* 73 */ array(), + /* 74 */ array(), + /* 75 */ array(), + /* 76 */ array(), + /* 77 */ array(), + /* 78 */ array(), + /* 79 */ array(), + /* 80 */ array(), + /* 81 */ array(), + /* 82 */ array(), + /* 83 */ array(), + /* 84 */ array(), + /* 85 */ array(), + /* 86 */ array(), + /* 87 */ array(), + /* 88 */ array(), + /* 89 */ array(), + /* 90 */ array(), + /* 91 */ array(), + /* 92 */ array(), + /* 93 */ array(), + /* 94 */ array(), + /* 95 */ array(), + /* 96 */ array(), + /* 97 */ array(), + /* 98 */ array(), + /* 99 */ array(), + /* 100 */ array(), + /* 101 */ array(), + /* 102 */ array(), + /* 103 */ array(), + /* 104 */ array(), + /* 105 */ array(), +); + static public $yy_default = array( + /* 0 */ 184, 128, 184, 184, 184, 184, 184, 184, 184, 184, + /* 10 */ 120, 131, 118, 184, 184, 184, 184, 114, 113, 184, + /* 20 */ 114, 184, 184, 184, 111, 184, 111, 184, 184, 184, + /* 30 */ 184, 184, 184, 184, 184, 142, 168, 169, 170, 171, + /* 40 */ 141, 166, 164, 167, 165, 129, 140, 183, 182, 109, + /* 50 */ 112, 116, 117, 115, 181, 180, 175, 174, 173, 176, + /* 60 */ 177, 179, 178, 172, 124, 126, 144, 143, 139, 145, + /* 70 */ 146, 149, 148, 147, 138, 137, 110, 108, 107, 119, + /* 80 */ 123, 136, 127, 125, 150, 151, 122, 121, 163, 162, + /* 90 */ 106, 130, 134, 133, 132, 161, 160, 154, 153, 152, + /* 100 */ 155, 156, 159, 158, 157, 135, +); +/* The next thing included is series of defines which control +** various aspects of the generated parser. +** self::YYNOCODE is a number which corresponds +** to no legal terminal or nonterminal number. This +** number is used to fill in empty slots of the hash +** table. +** self::YYFALLBACK If defined, this indicates that one or more tokens +** have fall-back values which should be used if the +** original value of the token will not parse. +** self::YYSTACKDEPTH is the maximum depth of the parser's stack. +** self::YYNSTATE the combined number of states. +** self::YYNRULE the number of rules in the grammar +** self::YYERRORSYMBOL is the code number of the error symbol. If not +** defined, then do no error processing. +*/ + const YYNOCODE = 79; + const YYSTACKDEPTH = 100; + const YYNSTATE = 106; + const YYNRULE = 78; + const YYERRORSYMBOL = 50; + const YYERRSYMDT = 'yy0'; + const YYFALLBACK = 0; + /** The next table maps tokens into fallback tokens. If a construct + * like the following: + * + * %fallback ID X Y Z. + * + * appears in the grammer, then ID becomes a fallback token for X, Y, + * and Z. Whenever one of the tokens X, Y, or Z is input to the parser + * but it does not parse, the type of the token is changed to ID and + * the parse is retried before an error is thrown. + */ + static public $yyFallback = array( + ); + /** + * Turn parser tracing on by giving a stream to which to write the trace + * and a prompt to preface each trace message. Tracing is turned off + * by making either argument NULL + * + * Inputs: + * + * - A stream resource to which trace output should be written. + * If NULL, then tracing is turned off. + * - A prefix string written at the beginning of every + * line of trace output. If NULL, then tracing is + * turned off. + * + * Outputs: + * + * - None. + * @param resource + * @param string + */ + static function Trace($TraceFILE, $zTracePrompt) + { + if (!$TraceFILE) { + $zTracePrompt = 0; + } elseif (!$zTracePrompt) { + $TraceFILE = 0; + } + self::$yyTraceFILE = $TraceFILE; + self::$yyTracePrompt = $zTracePrompt; + } + + /** + * Output debug information to output (php://output stream) + */ + static function PrintTrace() + { + self::$yyTraceFILE = fopen('php://output', 'w'); + self::$yyTracePrompt = ''; + } + + /** + * @var resource|0 + */ + static public $yyTraceFILE; + /** + * String to prepend to debug output + * @var string|0 + */ + static public $yyTracePrompt; + /** + * @var int + */ + public $yyidx; /* Index of top element in stack */ + /** + * @var int + */ + public $yyerrcnt; /* Shifts left before out of the error */ + /** + * @var array + */ + public $yystack = array(); /* The parser's stack */ + + /** + * For tracing shifts, the names of all terminals and nonterminals + * are required. The following table supplies these names + * @var array + */ + static public $yyTokenName = array( + '$', 'SELECT', 'AS_ALIAS', 'WHERE', + 'JOIN', 'ON', 'EQ', 'PAR_OPEN', + 'PAR_CLOSE', 'COMA', 'INTERVAL', 'F_DAY', + 'F_MONTH', 'F_YEAR', 'DOT', 'NAME', + 'NUMVAL', 'STRVAL', 'NOT_EQ', 'LOG_AND', + 'LOG_OR', 'GT', 'LT', 'GE', + 'LE', 'MATH_DIV', 'MATH_MULT', 'MATH_PLUS', + 'MATH_MINUS', 'LIKE', 'NOT_LIKE', 'IN', + 'NOT_IN', 'F_IF', 'F_ELT', 'F_COALESCE', + 'F_CONCAT', 'F_SUBSTR', 'F_TRIM', 'F_DATE', + 'F_DATE_FORMAT', 'F_CURRENT_DATE', 'F_NOW', 'F_TIME', + 'F_TO_DAYS', 'F_FROM_DAYS', 'F_DATE_ADD', 'F_DATE_SUB', + 'F_ROUND', 'F_FLOOR', 'error', 'result', + 'query', 'condition', 'class_name', 'join_statement', + 'where_statement', 'join_item', 'join_condition', 'field_id', + 'expression', 'operator', 'scalar', 'list_operator', + 'list', 'func_name', 'arg_list', 'scalar_list', + 'argument', 'interval_unit', 'num_scalar', 'str_scalar', + 'num_value', 'str_value', 'name', 'log_operator', + 'num_operator', 'str_operator', + ); + + /** + * For tracing reduce actions, the names of all rules are required. + * @var array + */ + static public $yyRuleName = array( + /* 0 */ "result ::= query", + /* 1 */ "result ::= condition", + /* 2 */ "query ::= SELECT class_name join_statement where_statement", + /* 3 */ "query ::= SELECT class_name AS_ALIAS class_name join_statement where_statement", + /* 4 */ "where_statement ::= WHERE condition", + /* 5 */ "where_statement ::=", + /* 6 */ "join_statement ::= join_item join_statement", + /* 7 */ "join_statement ::= join_item", + /* 8 */ "join_statement ::=", + /* 9 */ "join_item ::= JOIN class_name AS_ALIAS class_name ON join_condition", + /* 10 */ "join_item ::= JOIN class_name ON join_condition", + /* 11 */ "join_condition ::= field_id EQ field_id", + /* 12 */ "condition ::= expression", + /* 13 */ "expression ::= PAR_OPEN expression PAR_CLOSE", + /* 14 */ "expression ::= expression operator expression", + /* 15 */ "expression ::= scalar", + /* 16 */ "expression ::= field_id", + /* 17 */ "expression ::= expression list_operator list", + /* 18 */ "expression ::= func_name PAR_OPEN arg_list PAR_CLOSE", + /* 19 */ "list ::= PAR_OPEN scalar_list PAR_CLOSE", + /* 20 */ "scalar_list ::= scalar", + /* 21 */ "scalar_list ::= scalar_list COMA scalar", + /* 22 */ "arg_list ::=", + /* 23 */ "arg_list ::= argument", + /* 24 */ "arg_list ::= arg_list COMA argument", + /* 25 */ "argument ::= expression", + /* 26 */ "argument ::= INTERVAL expression interval_unit", + /* 27 */ "interval_unit ::= F_DAY", + /* 28 */ "interval_unit ::= F_MONTH", + /* 29 */ "interval_unit ::= F_YEAR", + /* 30 */ "scalar ::= num_scalar", + /* 31 */ "scalar ::= str_scalar", + /* 32 */ "num_scalar ::= num_value", + /* 33 */ "str_scalar ::= str_value", + /* 34 */ "field_id ::= class_name DOT name", + /* 35 */ "class_name ::= name", + /* 36 */ "name ::= NAME", + /* 37 */ "num_value ::= NUMVAL", + /* 38 */ "str_value ::= STRVAL", + /* 39 */ "operator ::= log_operator", + /* 40 */ "operator ::= num_operator", + /* 41 */ "operator ::= str_operator", + /* 42 */ "operator ::= EQ", + /* 43 */ "operator ::= NOT_EQ", + /* 44 */ "log_operator ::= LOG_AND", + /* 45 */ "log_operator ::= LOG_OR", + /* 46 */ "num_operator ::= GT", + /* 47 */ "num_operator ::= LT", + /* 48 */ "num_operator ::= GE", + /* 49 */ "num_operator ::= LE", + /* 50 */ "num_operator ::= MATH_DIV", + /* 51 */ "num_operator ::= MATH_MULT", + /* 52 */ "num_operator ::= MATH_PLUS", + /* 53 */ "num_operator ::= MATH_MINUS", + /* 54 */ "str_operator ::= LIKE", + /* 55 */ "str_operator ::= NOT_LIKE", + /* 56 */ "list_operator ::= IN", + /* 57 */ "list_operator ::= NOT_IN", + /* 58 */ "func_name ::= F_IF", + /* 59 */ "func_name ::= F_ELT", + /* 60 */ "func_name ::= F_COALESCE", + /* 61 */ "func_name ::= F_CONCAT", + /* 62 */ "func_name ::= F_SUBSTR", + /* 63 */ "func_name ::= F_TRIM", + /* 64 */ "func_name ::= F_DATE", + /* 65 */ "func_name ::= F_DATE_FORMAT", + /* 66 */ "func_name ::= F_CURRENT_DATE", + /* 67 */ "func_name ::= F_NOW", + /* 68 */ "func_name ::= F_TIME", + /* 69 */ "func_name ::= F_TO_DAYS", + /* 70 */ "func_name ::= F_FROM_DAYS", + /* 71 */ "func_name ::= F_YEAR", + /* 72 */ "func_name ::= F_MONTH", + /* 73 */ "func_name ::= F_DAY", + /* 74 */ "func_name ::= F_DATE_ADD", + /* 75 */ "func_name ::= F_DATE_SUB", + /* 76 */ "func_name ::= F_ROUND", + /* 77 */ "func_name ::= F_FLOOR", + ); + + /** + * This function returns the symbolic name associated with a token + * value. + * @param int + * @return string + */ + function tokenName($tokenType) + { + if ($tokenType === 0) { + return 'End of Input'; + } + if ($tokenType > 0 && $tokenType < count(self::$yyTokenName)) { + return self::$yyTokenName[$tokenType]; + } else { + return "Unknown"; + } + } + + /** + * The following function deletes the value associated with a + * symbol. The symbol can be either a terminal or nonterminal. + * @param int the symbol code + * @param mixed the symbol's value + */ + static function yy_destructor($yymajor, $yypminor) + { + switch ($yymajor) { + /* Here is inserted the actions which take place when a + ** terminal or non-terminal is destroyed. This can happen + ** when the symbol is popped from the stack during a + ** reduce or during error processing or when a parser is + ** being destroyed before it is finished parsing. + ** + ** Note: during a reduce, the only symbols destroyed are those + ** which appear on the RHS of the rule, but which are not used + ** inside the C code. + */ + default: break; /* If no destructor action specified: do nothing */ + } + } + + /** + * Pop the parser's stack once. + * + * If there is a destructor routine associated with the token which + * is popped from the stack, then call it. + * + * Return the major token number for the symbol popped. + * @param OQLParser_yyParser + * @return int + */ + function yy_pop_parser_stack() + { + if (!count($this->yystack)) { + return; + } + $yytos = array_pop($this->yystack); + if (self::$yyTraceFILE && $this->yyidx >= 0) { + fwrite(self::$yyTraceFILE, + self::$yyTracePrompt . 'Popping ' . self::$yyTokenName[$yytos->major] . + "\n"); + } + $yymajor = $yytos->major; + self::yy_destructor($yymajor, $yytos->minor); + $this->yyidx--; + return $yymajor; + } + + /** + * Deallocate and destroy a parser. Destructors are all called for + * all stack elements before shutting the parser down. + */ + function __destruct() + { + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + if (is_resource(self::$yyTraceFILE)) { + fclose(self::$yyTraceFILE); + } + } + + /** + * Based on the current state and parser stack, get a list of all + * possible lookahead tokens + * @param int + * @return array + */ + function yy_get_expected_tokens($token) + { + $state = $this->yystack[$this->yyidx]->stateno; + $expected = self::$yyExpectedTokens[$state]; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return $expected; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return array_unique($expected); + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate])) { + $expected += self::$yyExpectedTokens[$nextstate]; + if (in_array($token, + self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return array_unique($expected); + } + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new OQLParser_yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return array_unique($expected); + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return $expected; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + return array_unique($expected); + } + + /** + * Based on the parser state and current parser stack, determine whether + * the lookahead token is possible. + * + * The parser will convert the token value to an error token if not. This + * catches some unusual edge cases where the parser would fail. + * @param int + * @return bool + */ + function yy_is_expected_token($token) + { + if ($token === 0) { + return true; // 0 is not part of this + } + $state = $this->yystack[$this->yyidx]->stateno; + if (in_array($token, self::$yyExpectedTokens[$state], true)) { + return true; + } + $stack = $this->yystack; + $yyidx = $this->yyidx; + do { + $yyact = $this->yy_find_shift_action($token); + if ($yyact >= self::YYNSTATE && $yyact < self::YYNSTATE + self::YYNRULE) { + // reduce action + $done = 0; + do { + if ($done++ == 100) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // too much recursion prevents proper detection + // so give up + return true; + } + $yyruleno = $yyact - self::YYNSTATE; + $this->yyidx -= self::$yyRuleInfo[$yyruleno]['rhs']; + $nextstate = $this->yy_find_reduce_action( + $this->yystack[$this->yyidx]->stateno, + self::$yyRuleInfo[$yyruleno]['lhs']); + if (isset(self::$yyExpectedTokens[$nextstate]) && + in_array($token, self::$yyExpectedTokens[$nextstate], true)) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + if ($nextstate < self::YYNSTATE) { + // we need to shift a non-terminal + $this->yyidx++; + $x = new OQLParser_yyStackEntry; + $x->stateno = $nextstate; + $x->major = self::$yyRuleInfo[$yyruleno]['lhs']; + $this->yystack[$this->yyidx] = $x; + continue 2; + } elseif ($nextstate == self::YYNSTATE + self::YYNRULE + 1) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + if (!$token) { + // end of input: this is valid + return true; + } + // the last token was just ignored, we can't accept + // by ignoring input, this is in essence ignoring a + // syntax error! + return false; + } elseif ($nextstate === self::YY_NO_ACTION) { + $this->yyidx = $yyidx; + $this->yystack = $stack; + // input accepted, but not shifted (I guess) + return true; + } else { + $yyact = $nextstate; + } + } while (true); + } + break; + } while (true); + $this->yyidx = $yyidx; + $this->yystack = $stack; + return true; + } + + /** + * Find the appropriate action for a parser given the terminal + * look-ahead token iLookAhead. + * + * If the look-ahead token is YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return YY_NO_ACTION. + * @param int The look-ahead token + */ + function yy_find_shift_action($iLookAhead) + { + $stateno = $this->yystack[$this->yyidx]->stateno; + + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ + if (!isset(self::$yy_shift_ofst[$stateno])) { + // no shift actions + return self::$yy_default[$stateno]; + } + $i = self::$yy_shift_ofst[$stateno]; + if ($i === self::YY_SHIFT_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + if (count(self::$yyFallback) && $iLookAhead < count(self::$yyFallback) + && ($iFallback = self::$yyFallback[$iLookAhead]) != 0) { + if (self::$yyTraceFILE) { + fwrite(self::$yyTraceFILE, self::$yyTracePrompt . "FALLBACK " . + self::$yyTokenName[$iLookAhead] . " => " . + self::$yyTokenName[$iFallback] . "\n"); + } + return $this->yy_find_shift_action($iFallback); + } + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Find the appropriate action for a parser given the non-terminal + * look-ahead token $iLookAhead. + * + * If the look-ahead token is self::YYNOCODE, then check to see if the action is + * independent of the look-ahead. If it is, return the action, otherwise + * return self::YY_NO_ACTION. + * @param int Current state number + * @param int The look-ahead token + */ + function yy_find_reduce_action($stateno, $iLookAhead) + { + /* $stateno = $this->yystack[$this->yyidx]->stateno; */ + + if (!isset(self::$yy_reduce_ofst[$stateno])) { + return self::$yy_default[$stateno]; + } + $i = self::$yy_reduce_ofst[$stateno]; + if ($i == self::YY_REDUCE_USE_DFLT) { + return self::$yy_default[$stateno]; + } + if ($iLookAhead == self::YYNOCODE) { + return self::YY_NO_ACTION; + } + $i += $iLookAhead; + if ($i < 0 || $i >= self::YY_SZ_ACTTAB || + self::$yy_lookahead[$i] != $iLookAhead) { + return self::$yy_default[$stateno]; + } else { + return self::$yy_action[$i]; + } + } + + /** + * Perform a shift action. + * @param int The new state to shift in + * @param int The major token to shift in + * @param mixed the minor token to shift in + */ + function yy_shift($yyNewState, $yyMajor, $yypMinor) + { + $this->yyidx++; + if ($this->yyidx >= self::YYSTACKDEPTH) { + $this->yyidx--; + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sStack Overflow!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will execute if the parser + ** stack ever overflows */ + return; + } + $yytos = new OQLParser_yyStackEntry; + $yytos->stateno = $yyNewState; + $yytos->major = $yyMajor; + $yytos->minor = $yypMinor; + array_push($this->yystack, $yytos); + if (self::$yyTraceFILE && $this->yyidx > 0) { + fprintf(self::$yyTraceFILE, "%sShift %d\n", self::$yyTracePrompt, + $yyNewState); + fprintf(self::$yyTraceFILE, "%sStack:", self::$yyTracePrompt); + for($i = 1; $i <= $this->yyidx; $i++) { + fprintf(self::$yyTraceFILE, " %s", + self::$yyTokenName[$this->yystack[$i]->major]); + } + fwrite(self::$yyTraceFILE,"\n"); + } + } + + /** + * The following table contains information about every rule that + * is used during the reduce. + * + *
+     * array(
+     *  array(
+     *   int $lhs;         Symbol on the left-hand side of the rule
+     *   int $nrhs;     Number of right-hand side symbols in the rule
+     *  ),...
+     * );
+     * 
+ */ + static public $yyRuleInfo = array( + array( 'lhs' => 51, 'rhs' => 1 ), + array( 'lhs' => 51, 'rhs' => 1 ), + array( 'lhs' => 52, 'rhs' => 4 ), + array( 'lhs' => 52, 'rhs' => 6 ), + array( 'lhs' => 56, 'rhs' => 2 ), + array( 'lhs' => 56, 'rhs' => 0 ), + array( 'lhs' => 55, 'rhs' => 2 ), + array( 'lhs' => 55, 'rhs' => 1 ), + array( 'lhs' => 55, 'rhs' => 0 ), + array( 'lhs' => 57, 'rhs' => 6 ), + array( 'lhs' => 57, 'rhs' => 4 ), + array( 'lhs' => 58, 'rhs' => 3 ), + array( 'lhs' => 53, 'rhs' => 1 ), + array( 'lhs' => 60, 'rhs' => 3 ), + array( 'lhs' => 60, 'rhs' => 3 ), + array( 'lhs' => 60, 'rhs' => 1 ), + array( 'lhs' => 60, 'rhs' => 1 ), + array( 'lhs' => 60, 'rhs' => 3 ), + array( 'lhs' => 60, 'rhs' => 4 ), + array( 'lhs' => 64, 'rhs' => 3 ), + array( 'lhs' => 67, 'rhs' => 1 ), + array( 'lhs' => 67, 'rhs' => 3 ), + array( 'lhs' => 66, 'rhs' => 0 ), + array( 'lhs' => 66, 'rhs' => 1 ), + array( 'lhs' => 66, 'rhs' => 3 ), + array( 'lhs' => 68, 'rhs' => 1 ), + array( 'lhs' => 68, 'rhs' => 3 ), + array( 'lhs' => 69, 'rhs' => 1 ), + array( 'lhs' => 69, 'rhs' => 1 ), + array( 'lhs' => 69, 'rhs' => 1 ), + array( 'lhs' => 62, 'rhs' => 1 ), + array( 'lhs' => 62, 'rhs' => 1 ), + array( 'lhs' => 70, 'rhs' => 1 ), + array( 'lhs' => 71, 'rhs' => 1 ), + array( 'lhs' => 59, 'rhs' => 3 ), + array( 'lhs' => 54, 'rhs' => 1 ), + array( 'lhs' => 74, 'rhs' => 1 ), + array( 'lhs' => 72, 'rhs' => 1 ), + array( 'lhs' => 73, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 61, 'rhs' => 1 ), + array( 'lhs' => 75, 'rhs' => 1 ), + array( 'lhs' => 75, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 76, 'rhs' => 1 ), + array( 'lhs' => 77, 'rhs' => 1 ), + array( 'lhs' => 77, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 63, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + array( 'lhs' => 65, 'rhs' => 1 ), + ); + + /** + * The following table contains a mapping of reduce action to method name + * that handles the reduction. + * + * If a rule is not set, it has no handler. + */ + static public $yyReduceMap = array( + 0 => 0, + 1 => 0, + 2 => 2, + 3 => 3, + 4 => 4, + 5 => 5, + 8 => 5, + 6 => 6, + 7 => 7, + 9 => 9, + 10 => 10, + 11 => 11, + 12 => 12, + 16 => 12, + 25 => 12, + 27 => 12, + 28 => 12, + 29 => 12, + 30 => 12, + 31 => 12, + 13 => 13, + 14 => 14, + 17 => 14, + 15 => 15, + 58 => 15, + 59 => 15, + 60 => 15, + 61 => 15, + 62 => 15, + 63 => 15, + 64 => 15, + 65 => 15, + 66 => 15, + 67 => 15, + 68 => 15, + 69 => 15, + 70 => 15, + 71 => 15, + 72 => 15, + 73 => 15, + 74 => 15, + 75 => 15, + 76 => 15, + 77 => 15, + 18 => 18, + 19 => 19, + 20 => 20, + 23 => 20, + 21 => 21, + 24 => 21, + 22 => 22, + 26 => 26, + 32 => 32, + 33 => 32, + 34 => 34, + 35 => 35, + 37 => 35, + 39 => 35, + 40 => 35, + 41 => 35, + 42 => 35, + 43 => 35, + 44 => 35, + 45 => 35, + 46 => 35, + 47 => 35, + 48 => 35, + 49 => 35, + 50 => 35, + 51 => 35, + 52 => 35, + 53 => 35, + 54 => 35, + 55 => 35, + 56 => 35, + 57 => 35, + 36 => 36, + 38 => 38, + ); + /* Beginning here are the reduction cases. A typical example + ** follows: + ** #line + ** function yy_r0($yymsp){ ... } // User supplied code + ** #line + */ +#line 7 "oql-parser.y" + function yy_r0(){ $this->my_result = $this->yystack[$this->yyidx + 0]->minor; } +#line 1180 "oql-parser.php" +#line 10 "oql-parser.y" + function yy_r2(){ + $this->_retvalue = new OqlQuery($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); + } +#line 1185 "oql-parser.php" +#line 13 "oql-parser.y" + function yy_r3(){ + $this->_retvalue = new OqlQuery($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); + } +#line 1190 "oql-parser.php" +#line 17 "oql-parser.y" + function yy_r4(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1193 "oql-parser.php" +#line 18 "oql-parser.y" + function yy_r5(){ $this->_retvalue = null; } +#line 1196 "oql-parser.php" +#line 20 "oql-parser.y" + function yy_r6(){ + // insert the join statement on top of the existing list + array_unshift($this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -1]->minor); + // and return the updated array + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + } +#line 1204 "oql-parser.php" +#line 26 "oql-parser.y" + function yy_r7(){ + $this->_retvalue = Array($this->yystack[$this->yyidx + 0]->minor); + } +#line 1209 "oql-parser.php" +#line 32 "oql-parser.y" + function yy_r9(){ + // create an array with one single item + $this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -4]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); + } +#line 1215 "oql-parser.php" +#line 37 "oql-parser.y" + function yy_r10(){ + // create an array with one single item + $this->_retvalue = new OqlJoinSpec($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); + } +#line 1221 "oql-parser.php" +#line 42 "oql-parser.y" + function yy_r11(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, '=', $this->yystack[$this->yyidx + 0]->minor); } +#line 1224 "oql-parser.php" +#line 44 "oql-parser.y" + function yy_r12(){ $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } +#line 1227 "oql-parser.php" +#line 46 "oql-parser.y" + function yy_r13(){ $this->_retvalue = $this->yystack[$this->yyidx + -1]->minor; } +#line 1230 "oql-parser.php" +#line 47 "oql-parser.y" + function yy_r14(){ $this->_retvalue = new BinaryOqlExpression($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 1233 "oql-parser.php" +#line 48 "oql-parser.y" + function yy_r15(){ $this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; } +#line 1236 "oql-parser.php" +#line 51 "oql-parser.y" + function yy_r18(){ $this->_retvalue = new FunctionOqlExpression($this->yystack[$this->yyidx + -3]->minor, $this->yystack[$this->yyidx + -1]->minor); } +#line 1239 "oql-parser.php" +#line 54 "oql-parser.y" + function yy_r19(){ + $this->_retvalue = new ListOqlExpression($this->yystack[$this->yyidx + -1]->minor); + } +#line 1244 "oql-parser.php" +#line 57 "oql-parser.y" + function yy_r20(){ + $this->_retvalue = array($this->yystack[$this->yyidx + 0]->minor); + } +#line 1249 "oql-parser.php" +#line 60 "oql-parser.y" + function yy_r21(){ + array_push($this->yystack[$this->yyidx + -2]->minor, $this->yystack[$this->yyidx + 0]->minor); + $this->_retvalue = $this->yystack[$this->yyidx + -2]->minor; + } +#line 1255 "oql-parser.php" +#line 65 "oql-parser.y" + function yy_r22(){ + $this->_retvalue = array(); + } +#line 1260 "oql-parser.php" +#line 76 "oql-parser.y" + function yy_r26(){ $this->_retvalue = new IntervalOqlExpression($this->yystack[$this->yyidx + -1]->minor, $this->yystack[$this->yyidx + 0]->minor); } +#line 1263 "oql-parser.php" +#line 85 "oql-parser.y" + function yy_r32(){ $this->_retvalue = new ScalarOqlExpression($this->yystack[$this->yyidx + 0]->minor); } +#line 1266 "oql-parser.php" +#line 88 "oql-parser.y" + function yy_r34(){ $this->_retvalue = new FieldOqlExpression($this->m_iCol, $this->yystack[$this->yyidx + 0]->minor, $this->yystack[$this->yyidx + -2]->minor); } +#line 1269 "oql-parser.php" +#line 89 "oql-parser.y" + function yy_r35(){$this->_retvalue=$this->yystack[$this->yyidx + 0]->minor; } +#line 1272 "oql-parser.php" +#line 91 "oql-parser.y" + function yy_r36(){ + if ($this->yystack[$this->yyidx + 0]->minor[0] == '`') + { + $this->_retvalue = substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2); + } + else + { + $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; + } + } +#line 1284 "oql-parser.php" +#line 103 "oql-parser.y" + function yy_r38(){$this->_retvalue=stripslashes(substr($this->yystack[$this->yyidx + 0]->minor, 1, strlen($this->yystack[$this->yyidx + 0]->minor) - 2)); } +#line 1287 "oql-parser.php" + + /** + * placeholder for the left hand side in a reduce operation. + * + * For a parser with a rule like this: + *
+     * rule(A) ::= B. { A = 1; }
+     * 
+ * + * The parser will translate to something like: + * + * + * function yy_r0(){$this->_retvalue = 1;} + * + */ + private $_retvalue; + + /** + * Perform a reduce action and the shift that must immediately + * follow the reduce. + * + * For a rule such as: + * + *
+     * A ::= B blah C. { dosomething(); }
+     * 
+ * + * This function will first call the action, if any, ("dosomething();" in our + * example), and then it will pop three states from the stack, + * one for each entry on the right-hand side of the expression + * (B, blah, and C in our example rule), and then push the result of the action + * back on to the stack with the resulting state reduced to (as described in the .out + * file) + * @param int Number of the rule by which to reduce + */ + function yy_reduce($yyruleno) + { + //int $yygoto; /* The next state */ + //int $yyact; /* The next action */ + //mixed $yygotominor; /* The LHS of the rule reduced */ + //OQLParser_yyStackEntry $yymsp; /* The top of the parser's stack */ + //int $yysize; /* Amount to pop the stack */ + $yymsp = $this->yystack[$this->yyidx]; + if (self::$yyTraceFILE && $yyruleno >= 0 + && $yyruleno < count(self::$yyRuleName)) { + fprintf(self::$yyTraceFILE, "%sReduce (%d) [%s].\n", + self::$yyTracePrompt, $yyruleno, + self::$yyRuleName[$yyruleno]); + } + + $this->_retvalue = $yy_lefthand_side = null; + if (array_key_exists($yyruleno, self::$yyReduceMap)) { + // call the action + $this->_retvalue = null; + $this->{'yy_r' . self::$yyReduceMap[$yyruleno]}(); + $yy_lefthand_side = $this->_retvalue; + } + $yygoto = self::$yyRuleInfo[$yyruleno]['lhs']; + $yysize = self::$yyRuleInfo[$yyruleno]['rhs']; + $this->yyidx -= $yysize; + for($i = $yysize; $i; $i--) { + // pop all of the right-hand side parameters + array_pop($this->yystack); + } + $yyact = $this->yy_find_reduce_action($this->yystack[$this->yyidx]->stateno, $yygoto); + if ($yyact < self::YYNSTATE) { + /* If we are not debugging and the reduce action popped at least + ** one element off the stack, then we can push the new element back + ** onto the stack here, and skip the stack overflow test in yy_shift(). + ** That gives a significant speed improvement. */ + if (!self::$yyTraceFILE && $yysize) { + $this->yyidx++; + $x = new OQLParser_yyStackEntry; + $x->stateno = $yyact; + $x->major = $yygoto; + $x->minor = $yy_lefthand_side; + $this->yystack[$this->yyidx] = $x; + } else { + $this->yy_shift($yyact, $yygoto, $yy_lefthand_side); + } + } elseif ($yyact == self::YYNSTATE + self::YYNRULE + 1) { + $this->yy_accept(); + } + } + + /** + * The following code executes when the parse fails + * + * Code from %parse_fail is inserted here + */ + function yy_parse_failed() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sFail!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser fails */ + } + + /** + * The following code executes when a syntax error first occurs. + * + * %syntax_error code is inserted here + * @param int The major type of the error token + * @param mixed The minor type of the error token + */ + function yy_syntax_error($yymajor, $TOKEN) + { +#line 3 "oql-parser.y" + +throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN); +#line 1403 "oql-parser.php" + } + + /** + * The following is executed when the parser accepts + * + * %parse_accept code is inserted here + */ + function yy_accept() + { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sAccept!\n", self::$yyTracePrompt); + } + while ($this->yyidx >= 0) { + $stack = $this->yy_pop_parser_stack(); + } + /* Here code is inserted which will be executed whenever the + ** parser accepts */ + } + + /** + * The main parser program. + * + * The first argument is the major token number. The second is + * the token value string as scanned from the input. + * + * @param int the token number + * @param mixed the token value + * @param mixed any extra arguments that should be passed to handlers + */ + function doParse($yymajor, $yytokenvalue) + { +// $yyact; /* The parser action. */ +// $yyendofinput; /* True if we are at the end of input */ + $yyerrorhit = 0; /* True if yymajor has invoked an error */ + + /* (re)initialize the parser, if necessary */ + if ($this->yyidx === null || $this->yyidx < 0) { + /* if ($yymajor == 0) return; // not sure why this was here... */ + $this->yyidx = 0; + $this->yyerrcnt = -1; + $x = new OQLParser_yyStackEntry; + $x->stateno = 0; + $x->major = 0; + $this->yystack = array(); + array_push($this->yystack, $x); + } + $yyendofinput = ($yymajor==0); + + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sInput %s\n", + self::$yyTracePrompt, self::$yyTokenName[$yymajor]); + } + + do { + $yyact = $this->yy_find_shift_action($yymajor); + if ($yymajor < self::YYERRORSYMBOL && + !$this->yy_is_expected_token($yymajor)) { + // force a syntax error + $yyact = self::YY_ERROR_ACTION; + } + if ($yyact < self::YYNSTATE) { + $this->yy_shift($yyact, $yymajor, $yytokenvalue); + $this->yyerrcnt--; + if ($yyendofinput && $this->yyidx >= 0) { + $yymajor = 0; + } else { + $yymajor = self::YYNOCODE; + } + } elseif ($yyact < self::YYNSTATE + self::YYNRULE) { + $this->yy_reduce($yyact - self::YYNSTATE); + } elseif ($yyact == self::YY_ERROR_ACTION) { + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sSyntax Error!\n", + self::$yyTracePrompt); + } + if (self::YYERRORSYMBOL) { + /* A syntax error has occurred. + ** The response to an error depends upon whether or not the + ** grammar defines an error token "ERROR". + ** + ** This is what we do if the grammar does define ERROR: + ** + ** * Call the %syntax_error function. + ** + ** * Begin popping the stack until we enter a state where + ** it is legal to shift the error symbol, then shift + ** the error symbol. + ** + ** * Set the error count to three. + ** + ** * Begin accepting and shifting new tokens. No new error + ** processing will occur until three tokens have been + ** shifted successfully. + ** + */ + if ($this->yyerrcnt < 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $yymx = $this->yystack[$this->yyidx]->major; + if ($yymx == self::YYERRORSYMBOL || $yyerrorhit ){ + if (self::$yyTraceFILE) { + fprintf(self::$yyTraceFILE, "%sDiscard input token %s\n", + self::$yyTracePrompt, self::$yyTokenName[$yymajor]); + } + $this->yy_destructor($yymajor, $yytokenvalue); + $yymajor = self::YYNOCODE; + } else { + while ($this->yyidx >= 0 && + $yymx != self::YYERRORSYMBOL && + ($yyact = $this->yy_find_shift_action(self::YYERRORSYMBOL)) >= self::YYNSTATE + ){ + $this->yy_pop_parser_stack(); + } + if ($this->yyidx < 0 || $yymajor==0) { + $this->yy_destructor($yymajor, $yytokenvalue); + $this->yy_parse_failed(); + $yymajor = self::YYNOCODE; + } elseif ($yymx != self::YYERRORSYMBOL) { + $u2 = 0; + $this->yy_shift($yyact, self::YYERRORSYMBOL, $u2); + } + } + $this->yyerrcnt = 3; + $yyerrorhit = 1; + } else { + /* YYERRORSYMBOL is not defined */ + /* This is what we do if the grammar does not define ERROR: + ** + ** * Report an error message, and throw away the input token. + ** + ** * If the input token is $, then fail the parse. + ** + ** As before, subsequent error messages are suppressed until + ** three input tokens have been successfully shifted. + */ + if ($this->yyerrcnt <= 0) { + $this->yy_syntax_error($yymajor, $yytokenvalue); + } + $this->yyerrcnt = 3; + $this->yy_destructor($yymajor, $yytokenvalue); + if ($yyendofinput) { + $this->yy_parse_failed(); + } + $yymajor = self::YYNOCODE; + } + } else { + $this->yy_accept(); + $yymajor = self::YYNOCODE; + } + } while ($yymajor != self::YYNOCODE && $this->yyidx >= 0); + } +}#line 151 "oql-parser.y" + + + +class OQLParserException extends OQLException +{ + public function __construct($sInput, $iLine, $iCol, $sTokenName, $sTokenValue) + { + $sIssue = "Unexpected token $sTokenName"; + + parent::__construct($sIssue, $sInput, $iLine, $iCol, $sTokenValue); + } +} + +class OQLParser extends OQLParserRaw +{ + // dirty, but working for us (no other mean to get the final result :-( + protected $my_result; + + public function GetResult() + { + return $this->my_result; + } + + // More info on the source query and the current position while parsing it + // Data used when an exception is raised + protected $m_iLine; // still not used + protected $m_iCol; + protected $m_sSourceQuery; + + public function __construct($sQuery) + { + $this->m_iLine = 0; + $this->m_iCol = 0; + $this->m_sSourceQuery = $sQuery; + // no constructor - parent::__construct(); + } + + public function doParse($token, $value, $iCurrPosition = 0) + { + $this->m_iCol = $iCurrPosition; + + return parent::DoParse($token, $value); + } + + public function doFinish() + { + $this->doParse(0, 0); + return $this->my_result; + } + + public function __destruct() + { + // Bug in the original destructor, causing an infinite loop ! + // This is a real issue when a fatal error occurs on the first token (the error could not be seen) + if (is_null($this->yyidx)) + { + $this->yyidx = -1; + } + parent::__destruct(); + } +} + +#line 1620 "oql-parser.php" diff --git a/core/oql/oql-parser.y b/core/oql/oql-parser.y new file mode 100644 index 000000000..02df9f519 --- /dev/null +++ b/core/oql/oql-parser.y @@ -0,0 +1,213 @@ +%name OQLParser_ +%declare_class {class OQLParserRaw} +%syntax_error { +throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN); +} + +result ::= query(X). { $this->my_result = X; } +result ::= condition(X). { $this->my_result = X; } + +query(A) ::= SELECT class_name(X) join_statement(J) where_statement(W). { + A = new OqlQuery(X, X, W, J); +} +query(A) ::= SELECT class_name(X) AS_ALIAS class_name(Y) join_statement(J) where_statement(W). { + A = new OqlQuery(X, Y, W, J); +} + +where_statement(A) ::= WHERE condition(C). { A = C;} +where_statement(A) ::= . { A = null;} + +join_statement(A) ::= join_item(J) join_statement(S). { + // insert the join statement on top of the existing list + array_unshift(S, J); + // and return the updated array + A = S; +} +join_statement(A) ::= join_item(J). { + A = Array(J); +} +join_statement(A) ::= . { A = null;} + +join_item(A) ::= JOIN class_name(X) AS_ALIAS class_name(Y) ON join_condition(C). +{ + // create an array with one single item + A = new OqlJoinSpec(X, Y, C); +} +join_item(A) ::= JOIN class_name(X) ON join_condition(C). +{ + // create an array with one single item + A = new OqlJoinSpec(X, X, C); +} + +join_condition(A) ::= field_id(X) EQ field_id(Y). { A = new BinaryOqlExpression(X, '=', Y); } + +condition(A) ::= expression(X). { A = X; } + +expression(A) ::= PAR_OPEN expression(X) PAR_CLOSE. { A = X; } +expression(A) ::= expression(X) operator(Y) expression(Z). { A = new BinaryOqlExpression(X, Y, Z); } +expression(A) ::= scalar(X). { A=X; } +expression(A) ::= field_id(X). { A = X; } +expression(A) ::= expression(X) list_operator(Y) list(Z). { A = new BinaryOqlExpression(X, Y, Z); } +expression(A) ::= func_name(X) PAR_OPEN arg_list(Y) PAR_CLOSE. { A = new FunctionOqlExpression(X, Y); } + + +list(A) ::= PAR_OPEN scalar_list(X) PAR_CLOSE. { + A = new ListOqlExpression(X); +} +scalar_list(A) ::= scalar(X). { + A = array(X); +} +scalar_list(A) ::= scalar_list(L) COMA scalar(X). { + array_push(L, X); + A = L; +} + +arg_list(A) ::= . { + A = array(); +} +arg_list(A) ::= argument(X). { + A = array(X); +} +arg_list(A) ::= arg_list(L) COMA argument(X). { + array_push(L, X); + A = L; +} +argument(A) ::= expression(X). { A = X; } +argument(A) ::= INTERVAL expression(X) interval_unit(Y). { A = new IntervalOqlExpression(X, Y); } + +interval_unit(A) ::= F_DAY(X). { A = X; } +interval_unit(A) ::= F_MONTH(X). { A = X; } +interval_unit(A) ::= F_YEAR(X). { A = X; } + +scalar(A) ::= num_scalar(X). { A = X; } +scalar(A) ::= str_scalar(X). { A = X; } + +num_scalar(A) ::= num_value(X). { A = new ScalarOqlExpression(X); } +str_scalar(A) ::= str_value(X). { A = new ScalarOqlExpression(X); } + +field_id(A) ::= class_name(X) DOT name(Y). { A = new FieldOqlExpression($this->m_iCol, Y, X); } +class_name(A) ::= name(X). {A=X;} + +name(A) ::= NAME(X). { + if (X[0] == '`') + { + A = substr(X, 1, strlen(X) - 2); + } + else + { + A = X; + } +} + +num_value(A) ::= NUMVAL(X). {A=X;} +str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));} + +operator(A) ::= log_operator(X). {A=X;} +operator(A) ::= num_operator(X). {A=X;} +operator(A) ::= str_operator(X). {A=X;} +operator(A) ::= EQ(X). {A=X;} +operator(A) ::= NOT_EQ(X). {A=X;} + +log_operator(A) ::= LOG_AND(X). {A=X;} +log_operator(A) ::= LOG_OR(X). {A=X;} + +num_operator(A) ::= GT(X). {A=X;} +num_operator(A) ::= LT(X). {A=X;} +num_operator(A) ::= GE(X). {A=X;} +num_operator(A) ::= LE(X). {A=X;} +num_operator(A) ::= MATH_DIV(X). {A=X;} +num_operator(A) ::= MATH_MULT(X). {A=X;} +num_operator(A) ::= MATH_PLUS(X). {A=X;} +num_operator(A) ::= MATH_MINUS(X). {A=X;} + +str_operator(A) ::= LIKE(X). {A=X;} +str_operator(A) ::= NOT_LIKE(X). {A=X;} + +list_operator(A) ::= IN(X). {A=X;} +list_operator(A) ::= NOT_IN(X). {A=X;} + +func_name(A) ::= F_IF(X). { A=X; } +func_name(A) ::= F_ELT(X). { A=X; } +func_name(A) ::= F_COALESCE(X). { A=X; } +func_name(A) ::= F_CONCAT(X). { A=X; } +func_name(A) ::= F_SUBSTR(X). { A=X; } +func_name(A) ::= F_TRIM(X). { A=X; } +func_name(A) ::= F_DATE(X). { A=X; } +func_name(A) ::= F_DATE_FORMAT(X). { A=X; } +func_name(A) ::= F_CURRENT_DATE(X). { A=X; } +func_name(A) ::= F_NOW(X). { A=X; } +func_name(A) ::= F_TIME(X). { A=X; } +func_name(A) ::= F_TO_DAYS(X). { A=X; } +func_name(A) ::= F_FROM_DAYS(X). { A=X; } +func_name(A) ::= F_YEAR(X). { A=X; } +func_name(A) ::= F_MONTH(X). { A=X; } +func_name(A) ::= F_DAY(X). { A=X; } +func_name(A) ::= F_DATE_ADD(X). { A=X; } +func_name(A) ::= F_DATE_SUB(X). { A=X; } +func_name(A) ::= F_ROUND(X). { A=X; } +func_name(A) ::= F_FLOOR(X). { A=X; } + + +%code { + + +class OQLParserException extends OQLException +{ + public function __construct($sInput, $iLine, $iCol, $sTokenName, $sTokenValue) + { + $sIssue = "Unexpected token $sTokenName"; + + parent::__construct($sIssue, $sInput, $iLine, $iCol, $sTokenValue); + } +} + +class OQLParser extends OQLParserRaw +{ + // dirty, but working for us (no other mean to get the final result :-( + protected $my_result; + + public function GetResult() + { + return $this->my_result; + } + + // More info on the source query and the current position while parsing it + // Data used when an exception is raised + protected $m_iLine; // still not used + protected $m_iCol; + protected $m_sSourceQuery; + + public function __construct($sQuery) + { + $this->m_iLine = 0; + $this->m_iCol = 0; + $this->m_sSourceQuery = $sQuery; + // no constructor - parent::__construct(); + } + + public function doParse($token, $value, $iCurrPosition = 0) + { + $this->m_iCol = $iCurrPosition; + + return parent::DoParse($token, $value); + } + + public function doFinish() + { + $this->doParse(0, 0); + return $this->my_result; + } + + public function __destruct() + { + // Bug in the original destructor, causing an infinite loop ! + // This is a real issue when a fatal error occurs on the first token (the error could not be seen) + if (is_null($this->yyidx)) + { + $this->yyidx = -1; + } + parent::__destruct(); + } +} + +} diff --git a/core/oql/oqlexception.class.inc.php b/core/oql/oqlexception.class.inc.php new file mode 100644 index 000000000..3395df05f --- /dev/null +++ b/core/oql/oqlexception.class.inc.php @@ -0,0 +1,38 @@ +m_MyIssue = $sIssue; + $this->m_sInput = $sInput; + $this->m_iLine = $iLine; + $this->m_iCol = $iCol; + $this->m_sUnexpected = $sUnexpected; + $this->m_aExpecting = $aExpecting; + + if (is_null($this->m_aExpecting)) + { + $sMessage = "$sIssue - found '$sUnexpected' at $iCol in '$sInput'"; + } + else + { + $sExpectations = '{'.implode(', ', $aExpecting).'}'; + $sMessage = "$sIssue - found '$sUnexpected' at $iCol in '$sInput', expecting $sExpectations"; + } + + // make sure everything is assigned properly + parent::__construct($sMessage, 0); + } + + public function getHtmlDesc($sHighlightHtmlBegin = '', $sHighlightHtmlEnd = '') + { + $sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: "); + $sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol)); + $sRet .= $sHighlightHtmlBegin.htmlentities(substr($this->m_sInput, $this->m_iCol, strlen($this->m_sUnexpected))).$sHighlightHtmlEnd; + $sRet .= htmlentities(substr($this->m_sInput, $this->m_iCol + strlen($this->m_sUnexpected))); + return $sRet; + } +} + +?> diff --git a/core/oql/oqlinterpreter.class.inc.php b/core/oql/oqlinterpreter.class.inc.php new file mode 100644 index 000000000..b9a2ba5cc --- /dev/null +++ b/core/oql/oqlinterpreter.class.inc.php @@ -0,0 +1,55 @@ +m_sQuery = $sQuery; + } + + protected function Parse() + { + $oLexer = new OQLLexer($this->m_sQuery); + $oParser = new OQLParser($this->m_sQuery); + + while($oLexer->yylex()) + { + $oParser->doParse($oLexer->token, $oLexer->value, $oLexer->getTokenPos()); + } + $res = $oParser->doFinish(); + return $res; + } + + public function ParseQuery() + { + $oRes = $this->Parse(); + if (!$oRes instanceof OqlQuery) + { + throw new OqlException('Expecting an OQL query', $this->m_sQuery, 0, 0, get_class($oRes), array('OqlQuery')); + } + return $oRes; + } + + public function ParseExpression() + { + $oRes = $this->Parse(); + if (!$oRes instanceof Expression) + { + throw new OqlException('Expecting an OQL expression', $this->m_sQuery, 0, 0, get_class($oRes), array('Expression')); + } + return $oRes; + } +} + +?> diff --git a/core/oql/oqlquery.class.inc.php b/core/oql/oqlquery.class.inc.php new file mode 100644 index 000000000..5173704d7 --- /dev/null +++ b/core/oql/oqlquery.class.inc.php @@ -0,0 +1,106 @@ +m_sClass = $sClass; + $this->m_sClassAlias = $sClassAlias; + $this->m_oLeftField = $oExpression->GetLeftExpr(); + $this->m_oRightField = $oExpression->GetRightExpr(); + } + + public function GetClass() + { + return $this->m_sClass; + } + public function GetClassAlias() + { + return $this->m_sClassAlias; + } + public function GetLeftField() + { + return $this->m_oLeftField; + } + public function GetRightField() + { + return $this->m_oRightField; + } +} + +class BinaryOqlExpression extends BinaryExpression +{ +} + +class ScalarOqlExpression extends ScalarExpression +{ +} + +class FieldOqlExpression extends FieldExpression +{ + protected $m_iPosition; // position in the source string + + public function __construct($iPosition, $sName, $sParent = '') + { + $this->m_iPosition = $iPosition; + parent::__construct($sName, $sParent); + } + + public function GetPosition() + { + return $this->m_iPosition; + } +} + +class ListOqlExpression extends ListExpression +{ +} + +class FunctionOqlExpression extends FunctionExpression +{ +} + +class IntervalOqlExpression extends IntervalExpression +{ +} +class OqlQuery +{ + protected $m_sClass; + protected $m_sClassAlias; + protected $m_aJoins; // array of OqlJoinSpec + protected $m_oCondition; // condition tree (expressions) + + public function __construct($sClass, $sClassAlias = '', $oCondition = null, $aJoins = null) + { + $this->m_sClass = $sClass; + $this->m_sClassAlias = $sClassAlias; + $this->m_aJoins = $aJoins; + $this->m_oCondition = $oCondition; + } + + public function GetClass() + { + return $this->m_sClass; + } + public function GetClassAlias() + { + return $this->m_sClassAlias; + } + public function GetJoins() + { + return $this->m_aJoins; + } + public function GetCondition() + { + return $this->m_oCondition; + } +} + +?> diff --git a/core/sqlquery.class.inc.php b/core/sqlquery.class.inc.php new file mode 100644 index 000000000..4e747de53 --- /dev/null +++ b/core/sqlquery.class.inc.php @@ -0,0 +1,399 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +require_once('cmdbsource.class.inc.php'); + + +class SQLExpression extends BinaryExpression +{ +} +class ScalarSQLExpression extends ScalarExpression +{ +} +class TrueSQLExpression extends TrueExpression +{ +} +class FieldSQLExpression extends FieldExpression +{ +} + + + +class SQLQuery +{ + private $m_sTable = ''; + private $m_sTableAlias = ''; + private $m_aFields = array(); + private $m_oConditionExpr = null; + private $m_aFullTextNeedles = array(); + private $m_bToDelete = true; // The current table must be listed for deletion ? + private $m_aValues = array(); // Values to set in case of an update query + private $m_aJoinSelects = array(); + + public function __construct($sTable, $sTableAlias, $aFields, $oConditionExpr, $aFullTextNeedles, $bToDelete = true, $aValues = array()) + { + if (!CMDBSource::IsTable($sTable)) + { + trigger_error("Unknown table '$sTable'", E_USER_ERROR); + } + // $aFields must be an array of "alias"=>"expr" + // $oConditionExpr must be a condition tree + // $aValues is an array of "alias"=>value + + $this->m_sTable = $sTable; + $this->m_sTableAlias = $sTableAlias; + $this->m_aFields = $aFields; + $this->m_oConditionExpr = $oConditionExpr; + if (is_null($oConditionExpr)) + { + $this->m_oConditionExpr = new TrueExpression; + } + else if (!$oConditionExpr instanceof Expression) + { + throw new CoreException('Invalid type for condition, expecting an Expression', array('class' => get_class($oConditionExpr))); + } + $this->m_aFullTextNeedles = $aFullTextNeedles; + $this->m_bToDelete = $bToDelete; + $this->m_aValues = $aValues; + } + + public function DisplayHtml() + { + if (count($this->m_aFields) == 0) $sFields = ""; + else + { + $aFieldDesc = array(); + foreach ($this->m_aFields as $sAlias => $oExpression) + { + $aFieldDesc[] = $oExpression->Render()." as $sAlias"; + } + $sFields = " => ".implode(', ', $aFieldDesc); + } + echo "$this->m_sTable$sFields
\n"; + // #@# todo - display html of an expression tree + //$this->m_oConditionExpr->DisplayHtml() + if (count($this->m_aFullTextNeedles) > 0) + { + echo "Full text criteria...
\n"; + echo "
    \n"; + foreach ($this->m_aFullTextNeedles as $sFTNeedle) + { + echo "
  • $sFTNeedle
  • \n"; + } + echo "
"; + } + if (count($this->m_aJoinSelects) > 0) + { + echo "Joined to...
\n"; + echo "
    \n"; + foreach ($this->m_aJoinSelects as $aJoinInfo) + { + $sJoinType = $aJoinInfo["jointype"]; + $oSQLQuery = $aJoinInfo["select"]; + $sLeftField = $aJoinInfo["leftfield"]; + $sRightField = $aJoinInfo["rightfield"]; + + echo "
  • Join '$sJoinType', $sLeftField, $sRightField".$oSQLQuery->DisplayHtml()."
  • \n"; + } + echo "
"; + } + $aFrom = array(); + $aFields = array(); + $oCondition = null; + $aDelTables = array(); + $aSetValues = array(); + $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); + echo "From ...
\n"; + echo "
\n";
+		print_r($aFrom);
+		echo "
"; + } + + public function SetCondition($oConditionExpr) + { + $this->m_oConditionExpr = $oConditionExpr; + } + + public function AddCondition($oConditionExpr) + { + $this->m_oConditionExpr->LogAnd($oConditionExpr); + } + + private function AddJoin($sJoinType, $oSQLQuery, $sLeftField, $sRightField) + { + assert((get_class($oSQLQuery) == __CLASS__) || is_subclass_of($oSQLQuery, __CLASS__)); + if (!CMDBSource::IsField($this->m_sTable, $sLeftField)) + { + trigger_error("Unknown field '$sLeftField' in table '".$this->m_sTable, E_USER_ERROR); + } + if (!CMDBSource::IsField($oSQLQuery->m_sTable, $sRightField)) + { + trigger_error("Unknown field '$sRightField' in table '".$oSQLQuery->m_sTable."'", E_USER_ERROR); + } + + $this->m_aJoinSelects[] = array( + "jointype" => $sJoinType, + "select" => $oSQLQuery, + "leftfield" => $sLeftField, + "rightfield" => $sRightField + ); + } + public function AddInnerJoin($oSQLQuery, $sLeftField, $sRightField) + { + $this->AddJoin("inner", $oSQLQuery, $sLeftField, $sRightField); + } + public function AddLeftJoin($oSQLQuery, $sLeftField, $sRightField) + { + return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField); + } + + // Interface, build the SQL query + public function RenderDelete() + { + // The goal will be to complete the list as we build the Joins + $aFrom = array(); + $aFields = array(); + $oCondition = null; + $aDelTables = array(); + $aSetValues = array(); + $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); + + // Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ... + + $sDelete = self::ClauseDelete($aDelTables); + $sFrom = self::ClauseFrom($aFrom); + // #@# safety net to redo ? + /* + if ($this->m_oConditionExpr->IsAny()) + -- if (count($aConditions) == 0) -- + { + trigger_error("Building a request wich will delete every object of a given table -looks suspicious- please use truncate instead...", E_USER_ERROR); + } + */ + $sWhere = self::ClauseWhere($oCondition); + return "DELETE $sDelete FROM $sFrom WHERE $sWhere"; + } + + // Interface, build the SQL query + public function RenderUpdate() + { + // The goal will be to complete the list as we build the Joins + $aFrom = array(); + $aFields = array(); + $oCondition = null; + $aDelTables = array(); + $aSetValues = array(); + $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); + + $sFrom = self::ClauseFrom($aFrom); + $sValues = self::ClauseValues($aSetValues); + $sWhere = self::ClauseWhere($oCondition); + return "UPDATE $sFrom SET $sValues WHERE $sWhere"; + } + + // Interface, build the SQL query + public function RenderSelect($aOrderBy = array()) + { + // The goal will be to complete the lists as we build the Joins + $aFrom = array(); + $aFields = array(); + $oCondition = null; + $aDelTables = array(); + $aSetValues = array(); + $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues); + + $sSelect = self::ClauseSelect($aFields); + $sFrom = self::ClauseFrom($aFrom); + $sWhere = self::ClauseWhere($oCondition); + $sOrderBy = self::ClauseOrderBy($aOrderBy); + if (!empty($sOrderBy)) + { + $sOrderBy = "ORDER BY $sOrderBy"; + } + return "SELECT DISTINCT $sSelect FROM $sFrom WHERE $sWhere $sOrderBy"; + } + + private static function ClauseSelect($aFields) + { + $aSelect = array(); + foreach ($aFields as $sFieldAlias => $sSQLExpr) + { + $aSelect[] = "$sSQLExpr AS $sFieldAlias"; + } + $sSelect = implode(', ', $aSelect); + return $sSelect; + } + + private static function ClauseDelete($aDelTableAliases) + { + $aDelTables = array(); + foreach ($aDelTableAliases as $sTableAlias) + { + $aDelTables[] = "$sTableAlias"; + } + $sDelTables = implode(', ', $aDelTables); + return $sDelTables; + } + + private static function ClauseFrom($aFrom) + { + $sFrom = ""; + foreach ($aFrom as $sTableAlias => $aJoinInfo) + { + switch ($aJoinInfo["jointype"]) + { + case "first": + $sFrom .= "`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; + $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]); + break; + case "inner": + $sFrom .= " INNER JOIN `".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; + $sFrom .= " ON ".$aJoinInfo["joincondition"]; + $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]); + break; + case "left": + $sFrom .= " LEFT JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; + $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]); + $sFrom .= ") ON ".$aJoinInfo["joincondition"]; + break; + default: + trigger_error("Unknown jointype: '".$aJoinInfo["jointype"]."'"); + } + } + return $sFrom; + } + + private static function ClauseValues($aValues) + { + $aSetValues = array(); + foreach ($aValues as $sFieldSpec => $value) + { + $aSetValues[] = "$sFieldSpec = ".CMDBSource::Quote($value); + } + $sSetValues = implode(', ', $aSetValues); + return $sSetValues; + } + + private static function ClauseWhere($oConditionExpr) + { + return $oConditionExpr->Render(); + } + + private static function ClauseOrderBy($aOrderBy) + { + $aOrderBySpec = array(); + foreach($aOrderBy as $sFieldAlias => $bAscending) + { + $aOrderBySpec[] = '`'.$sFieldAlias.'`'.($bAscending ? " ASC" : " DESC"); + } + $sOrderBy = implode(", ", $aOrderBySpec); + return $sOrderBy; + } + + // Purpose: prepare the query data, once for all + private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues) + { + $sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues); + + // Add the full text search condition, based on each and every requested field + // + // To be updated with a real full text search based on the mySQL settings + // (then it might move somewhere else !) + // + $oCondition = $this->m_oConditionExpr; + if ((count($aFields) > 0) && (count($this->m_aFullTextNeedles) > 0)) + { + $aFieldExp = array(); + foreach ($aFields as $sField) + { + // This is TEMPORARY (that's why it is weird, actually) + // Full text match will be done as an expression in the filter condition + + // $sField is already a string `table`.`column` + // Let's make an expression out of it (again !) + $aFieldExp[] = Expression::FromOQL($sField); + } + $oFullTextExpr = new CharConcatExpression($aFieldExp); + // The cast is necessary because the CONCAT result in a binary string: + // if any of the field is a binary string => case sensitive comparison + // + foreach($this->m_aFullTextNeedles as $sFTNeedle) + { + $oNewCond = new BinaryExpression($oFullTextExpr, 'LIKE', new ScalarExpression("%$sFTNeedle%")); + $oCondition = $oCondition->LogAnd($oNewCond); + } + } + + return $sTableAlias; + } + + private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, $sJoinType = "first", $sCallerAlias = "", $sLeftField = "", $sRightField = "") + { + $aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable); + + $aTranslationTable[$this->m_sTable]['*'] = $this->m_sTableAlias; + + // Handle the various kinds of join (or first table in the list) + // + $sJoinCond = "`$sCallerAlias`.`$sLeftField` = `{$this->m_sTableAlias}`.`$sRightField`"; + switch ($sJoinType) + { + case "first": + $aFrom[$this->m_sTableAlias] = array("jointype"=>"first", "tablename"=>$this->m_sTable, "joincondition"=>""); + break; + case "inner": + case "left": + $aFrom[$this->m_sTableAlias] = array("jointype"=>$sJoinType, "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond"); + break; + } + + // Given the alias, modify the fields and conditions + // before adding them into the current lists + // + foreach($this->m_aFields as $sAlias => $oExpression) + { + $sTable = $oExpression->GetParent(); + $sColumn = $oExpression->GetName(); + $aFields["`$sAlias`"] = $oExpression->Render(); + } + if ($this->m_bToDelete) + { + $aDelTables[] = "`{$this->m_sTableAlias}`"; + } + foreach($this->m_aValues as $sFieldName=>$value) + { + $aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further! + } + + // loop on joins, to complete the list of tables/fields/conditions + // + $aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query + foreach ($this->m_aJoinSelects as $aJoinData) + { + $sJoinType = $aJoinData["jointype"]; + $oRightSelect = $aJoinData["select"]; + $sLeftField = $aJoinData["leftfield"]; + $sRightField = $aJoinData["rightfield"]; + + $sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $sJoinType, $this->m_sTableAlias, $sLeftField, $sRightField); + } + $aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom; + + return $this->m_sTableAlias; + } + +} + +?> diff --git a/core/stimulus.class.inc.php b/core/stimulus.class.inc.php new file mode 100644 index 000000000..ee22fdd81 --- /dev/null +++ b/core/stimulus.class.inc.php @@ -0,0 +1,59 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +class ObjectStimulus +{ + private $m_aParams = array(); + + public function __construct($aParams) + { + $this->m_aParams = $aParams; + $this->ConsistencyCheck(); + } + + public function Get($sParamName) {return $this->m_aParams[$sParamName];} + + // Note: I could factorize this code with the parameter management made for the AttributeDef class + // to be overloaded + static protected function ListExpectedParams() + { + return array("label", "description"); + } + + private function ConsistencyCheck() + { + + // Check that any mandatory param has been specified + // + $aExpectedParams = $this->ListExpectedParams(); + foreach($aExpectedParams as $sParamName) + { + if (!array_key_exists($sParamName, $this->m_aParams)) + { + $aBacktrace = debug_backtrace(); + $sTargetClass = $aBacktrace[2]["class"]; + $sCodeInfo = $aBacktrace[1]["file"]." - ".$aBacktrace[1]["line"]; + trigger_error("ERROR missing parameter '$sParamName' in ".get_class($this)." declaration for class $sTargetClass ($sCodeInfo)
\n", E_USER_ERROR); + } + } + } +} + + + +class StimulusUserAction extends ObjectStimulus +{ +} + +?> diff --git a/core/test.class.inc.php b/core/test.class.inc.php new file mode 100644 index 000000000..e5cffe37f --- /dev/null +++ b/core/test.class.inc.php @@ -0,0 +1,430 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +class ExceptionFromError extends Exception +{ + public function getTraceAsHtml() + { + $aBackTrace = $this->getTrace(); + return MyHelpers::get_callstack_html(0, $this->getTrace()); + // return "
\n".$this->getTraceAsString()."
\n"; + } +} + + +/** + * Test handler API and basic helpers + * + * @package iTopORM + * @author Romain Quetiez + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ +abstract class TestHandler +{ + protected $m_aSuccesses; + protected $m_aWarnings; + protected $m_aErrors; + protected $m_sOutput; + + public function __construct() + { + $this->m_aSuccesses = array(); + $this->m_aWarnings = array(); + $this->m_aErrors = array(); + } + + abstract static public function GetName(); + abstract static public function GetDescription(); + + protected function DoPrepare() {return true;} + abstract protected function DoExecute(); + protected function DoCleanup() {return true;} + + protected function ReportSuccess($sMessage, $sSubtestId = '') + { + $this->m_aSuccesses[] = $sMessage; + } + + protected function ReportWarning($sMessage, $sSubtestId = '') + { + $this->m_aWarnings[] = $sMessage; + } + + protected function ReportError($sMessage, $sSubtestId = '') + { + $this->m_aErrors[] = $sMessage; + } + + public function GetResults() + { + return $this->m_aSuccesses; + } + + public function GetWarnings() + { + return $this->m_aWarnings; + } + + public function GetErrors() + { + return $this->m_aErrors; + } + + public function GetOutput() + { + return $this->m_sOutput; + } + + public function error_handler($errno, $errstr, $errfile, $errline) + { + // Note: return false to call the default handler (stop the program if an error) + + switch ($errno) + { + case E_USER_ERROR: + $this->ReportError($errstr); + //throw new ExceptionFromError("Fatal error in line $errline of file $errfile: $errstr"); + break; + case E_USER_WARNING: + $this->ReportWarning($errstr); + break; + case E_USER_NOTICE: + $this->ReportWarning($errstr); + break; + default: + throw new ExceptionFromError("Fatal warning in line $errline of file $errfile: $errstr"); + $this->ReportWarning("Unknown error type: [$errno] $errstr"); + echo "Unknown error type: [$errno] $errstr
\n"; + break; + } + return true; // do not call the default handler + } + + public function Execute() + { + ob_start(); + set_error_handler(array($this, 'error_handler')); + try + { + $this->DoPrepare(); + $this->DoExecute(); + } + catch (ExceptionFromError $e) + { + $this->ReportError($e->getMessage().' - '.$e->getTraceAsHtml()); + } + catch (Exception $e) + { + //$this->ReportError($e->getMessage()); + //$this->ReportError($e->__tostring()); + $this->ReportError($e->getMessage().' - '.$e->getTraceAsString()); + } + restore_error_handler(); + $this->m_sOutput = ob_get_clean(); + return (count($this->GetErrors()) == 0); + } +} + +/** + * Test to execute a piece of code (checks if an error occurs) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestFunction extends TestHandler +{ + // simply overload DoExecute (temporary) +} + +/** + * Test to check that a function outputs some values depending on its input + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestFunctionInOut extends TestFunction +{ + abstract static public function GetCallSpec(); // parameters to call_user_func + abstract static public function GetInOut(); // array of input => output + + protected function DoExecute() + { + $aTests = $this->GetInOut(); + if (is_array($aTests)) + { + foreach ($aTests as $iTestId => $aTest) + { + $ret = call_user_func_array($this->GetCallSpec(), $aTest['args']); + if ($ret != $aTest['output']) + { + // Note: to be improved to cope with non string parameters + $this->ReportError("Found '$ret' while expecting '".$aTest['output']."'", $iTestId); + } + else + { + $this->ReportSuccess("Found the expected output '$ret'", $iTestId); + } + } + } + else + { + $ret = call_user_func($this->GetCallSpec()); + $this->ReportSuccess('Finished successfully'); + } + } +} + + +/** + * Test to check an URL (Searches for Error/Warning/Etc keywords) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestUrl extends TestHandler +{ + abstract static public function GetUrl(); + abstract static public function GetErrorKeywords(); + abstract static public function GetWarningKeywords(); + + protected function DoExecute() + { + return true; + } +} + + +/** + * Test to check a user management module + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestUserRights extends TestHandler +{ + protected function DoExecute() + { + return true; + } +} + + +/** + * Test to execute a scenario on a given DB + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestScenarioOnDB extends TestHandler +{ + abstract static public function GetDBHost(); + abstract static public function GetDBUser(); + abstract static public function GetDBPwd(); + abstract static public function GetDBName(); + + protected function DoPrepare() + { + $sDBHost = $this->GetDBHost(); + $sDBUser = $this->GetDBUser(); + $sDBPwd = $this->GetDBPwd(); + $sDBName = $this->GetDBName(); + + CMDBSource::Init($sDBHost, $sDBUser, $sDBPwd); + if (CMDBSource::IsDB($sDBName)) + { + CMDBSource::DropDB($sDBName); + } + CMDBSource::CreateDB($sDBName); + } + + protected function DoCleanup() + { + // CMDBSource::DropDB($this->GetDBName()); + } +} + + +/** + * Test to use a business model on a given DB + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestBizModel extends TestHandler +{ +// abstract static public function GetDBSubName(); +// abstract static public function GetBusinessModelFile(); + abstract static public function GetConfigFile(); + + protected function DoPrepare() + { + MetaModel::Startup($this->GetConfigFile(), true); // allow missing DB + MetaModel::CheckDefinitions(); + + // something here to create records... but that's another story + } + + protected function ResetDB() + { + if (MetaModel::DBExists()) + { + MetaModel::DBDrop(); + } + MetaModel::DBCreate(); + } + + static protected function show_list($oObjectSet) + { + $oObjectSet->Rewind(); + while ($oItem = $oObjectSet->Fetch()) + { + $aValues = array(); + foreach(MetaModel::GetAttributesList(get_class($oItem)) as $sAttCode) + { + $aValues[] = $oItem->GetAsHTML($sAttCode); + } + echo $oItem->GetKey()." => ".implode(", ", $aValues)."
\n"; + } + } + + static protected function search_and_show_list(DBObjectSearch $oMyFilter) + { + $oObjSet = new CMDBObjectSet($oMyFilter); + echo $oMyFilter->__DescribeHTML()."' - Found ".$oObjSet->Count()." items.
\n"; + self::show_list($oObjSet); + } + + static protected function search_and_show_list_from_sibusql($sSibuSQL) + { + echo $sSibuSQL."...
\n"; + $oNewFilter = DBObjectSearch::FromSibuSQL($sSibuSQL); + self::search_and_show_list($oNewFilter); + } +} + + +/** + * Test to execute a scenario common to any business model (tries to build all the possible queries, etc.) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class TestBizModelGeneric extends TestBizModel +{ + static public function GetName() + { + return 'Full test on a given business model'; + } + + static public function GetDescription() + { + return 'Systematic tests: gets each and every existing class and tries every attribute, search filters, etc.'; + } + + protected function DoPrepare() + { + parent::DoPrepare(); + + if (!MetaModel::DBExists()) + { + MetaModel::DBCreate(); + } + // something here to create records... but that's another story + } + + protected function DoExecute() + { + foreach(MetaModel::GetClasses() as $sClassName) + { + if (MetaModel::IsAbstract($sClassName)) continue; + + $oNobody = MetaModel::GetObject($sClassName, 123); + $oBaby = new $sClassName; + $oFilter = new DBObjectSearch($sClassName); + + // Challenge reversibility of SibusQL / filter object + // + $sExpr1 = $oFilter->ToSibuSQL(); + $oNewFilter = DBObjectSearch::FromSibuSQL($sExpr1); + $sExpr2 = $oNewFilter->ToSibuSQL(); + if ($sExpr1 != $sExpr2) + { + $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: $sExpr1 != $sExpr2"); + } + + // Use the filter (perform the query) + // + $oSet = new CMDBObjectSet($oFilter); + $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName"); + } + return true; + } +} + + +?> diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php new file mode 100644 index 000000000..61fc7ef6f --- /dev/null +++ b/core/userrights.class.inc.php @@ -0,0 +1,205 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +class UserRightException extends CoreException +{ +} + + +define('UR_ALLOWED_NO', 0); +define('UR_ALLOWED_YES', 1); +define('UR_ALLOWED_DEPENDS', 2); + +define('UR_ACTION_READ', 1); // View an object +define('UR_ACTION_MODIFY', 2); // Create/modify an object/attribute +define('UR_ACTION_DELETE', 3); // Delete an object + +define('UR_ACTION_BULK_READ', 4); // Export multiple objects +define('UR_ACTION_BULK_MODIFY', 5); // Create/modify multiple objects +define('UR_ACTION_BULK_DELETE', 6); // Delete multiple objects + +define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions (CSV import, View schema...) + +/** + * User management module API + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +abstract class UserRightsAddOnAPI +{ + abstract public function Setup(); // initial installation + abstract public function Init(); // loads data (possible optimizations) + abstract public function CheckCredentials($iUserId, $sPassword); // returns the id of the user or false + abstract public function GetFilter($iUserId, $sClass); // returns a filter object + abstract public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $aInstances); + abstract public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $aInstances); + abstract public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances); +} + + + +/** + * User management core API + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class UserRights +{ + protected static $m_oAddOn; + protected static $m_sUser; + protected static $m_sRealUser; + protected static $m_iUserId; + protected static $m_iRealUserId; + + public static function SelectModule($sModuleName) + { + if (!class_exists($sModuleName)) + { + trigger_error("Could not select this module, '$sModuleName' in not a valid class name", E_USER_ERROR); + return; + } + if (!is_subclass_of($sModuleName, 'UserRightsAddOnAPI')) + { + trigger_error("Could not select this module, the class '$sModuleName' is not derived from UserRightsAddOnAPI", E_USER_ERROR); + return; + } + self::$m_oAddOn = new $sModuleName; + self::$m_oAddOn->Init(); + self::$m_sUser = ''; + self::$m_sRealUser = ''; + self::$m_iUserId = 0; + self::$m_iRealUserId = 0; + } + + // Installation (e.g: give default values for users) + public static function Setup() + { + // to be discussed... + return self::$m_oAddOn->Setup(); + } + + protected static function IsLoggedIn() + { + return (!empty(self::$m_sUser)); + } + + public static function Login($sName, $sPassword) + { + self::$m_iUserId = self::$m_oAddOn->CheckCredentials($sName, $sPassword); + if ( self::$m_iUserId !== false ) + { + self::$m_sUser = $sName; + self::$m_iRealUserId = self::$m_iUserId; + self::$m_sRealUser = $sName; + return true; + } + else + { + return false; + } + } + + public static function Impersonate($sName, $sPassword) + { + if (!self::CheckLogin()) return false; + + self::$m_iRealUserId = self::$m_oAddOn->CheckCredentials($sName, $sPassword); + if ( self::$m_iRealUserId !== false) + { + self::$m_sUser = $sName; + return true; + } + else + { + return false; + } + } + + public static function GetUser() + { + return self::$m_sUser; + } + + public static function GetUserId() + { + return self::$m_iUserId; + } + + public static function GetRealUser() + { + return self::$m_sRealUser; + } + + public static function GetRealUserId() + { + return self::$m_iRealUserId; + } + + protected static function CheckLogin() + { + if (!self::IsLoggedIn()) + { + //throw new UserRightException('No user logged in', array()); + return false; + } + return true; + } + + + public static function GetFilter($sClass) + { + if (!MetaModel::HasCategory($sClass, 'bizModel')) return new DBObjectSearch($sClass); + if (!self::CheckLogin()) return false; + + return self::$m_oAddOn->GetFilter(self::$m_iUserId, $sClass); + } + + public static function IsActionAllowed($sClass, $iActionCode, dbObjectSet $aInstances) + { + if (!MetaModel::HasCategory($sClass, 'bizModel')) return true; + if (!self::CheckLogin()) return false; + + return self::$m_oAddOn->IsActionAllowed(self::$m_iUserId, $sClass, $iActionCode, $aInstances); + } + + public static function IsStimulusAllowed($sClass, $sStimulusCode, dbObjectSet $aInstances) + { + if (!MetaModel::HasCategory($sClass, 'bizModel')) return true; + if (!self::CheckLogin()) return false; + + return self::$m_oAddOn->IsStimulusAllowed(self::$m_iUserId, $sClass, $sStimulusCode, $aInstances); + } + + public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances) + { + if (!MetaModel::HasCategory($sClass, 'bizModel')) return true; + if (!self::CheckLogin()) return false; + + return self::$m_oAddOn->IsActionAllowedOnAttribute(self::$m_iUserId, $sClass, $sAttCode, $iActionCode, $aInstances); + } +} + + +?> diff --git a/core/valuesetdef.class.inc.php b/core/valuesetdef.class.inc.php new file mode 100644 index 000000000..c541683cc --- /dev/null +++ b/core/valuesetdef.class.inc.php @@ -0,0 +1,238 @@ + + * @author Denis Flaven + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version 1.1.1.1 $ + */ + +require_once('MyHelpers.class.inc.php'); + +abstract class ValueSetDefinition +{ + protected $m_bIsLoaded = false; + protected $m_aValues = array(); + protected $m_aArgsObj = array(); + protected $m_aArgsApp = array(); + + + // Displayable description that could be computed out of the std usage context + public function GetValuesDescription() + { + $aValues = $this->GetValues(array(), ''); + $aDisplayedValues = array(); + foreach($aValues as $key => $value) + { + $aDisplayedValues[] = "$key => $value"; + } + $sAllowedValues = implode(', ', $aDisplayedValues); + return $sAllowedValues; + } + + + public function GetValues($aArgs, $sBeginsWith) + { + if (!$this->m_bIsLoaded) + { + $this->LoadValues($aArgs); + $this->m_bIsLoaded = true; + } + if (strlen($sBeginsWith) == 0) + { + $aRet = $this->m_aValues; + } + else + { + $iCheckedLen = strlen($sBeginsWith); + $sBeginsWith = strtolower($sBeginsWith); + $aRet = array(); + foreach ($this->m_aValues as $sKey=>$sValue) + { + if (strtolower(substr($sValue, 0, $iCheckedLen)) == $sBeginsWith) + { + $aRet[$sKey] = $sValue; + } + } + } + return $aRet; + } + + public function ListArgsFromContextApp() + { + return $this->m_aArgsObj; + } + public function ListArgsFromContextObj() + { + return $this->m_aArgsApp; + } + + abstract protected function LoadValues($aArgs); +} + + +/** + * Set of existing values for an attribute, given a search filter + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class ValueSetObjects extends ValueSetDefinition +{ + protected $m_sFilterExpr; // in SibuSQL + protected $m_sValueAttCode; + protected $m_aOrderBy; + + public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array()) + { + $this->m_sFilterExpr = $sFilterExp; + $this->m_sValueAttCode = $sValueAttCode; + $this->m_aOrderBy = $aOrderBy; + } + + protected function LoadValues($aArgs) + { + $this->m_aValues = array(); + + $oFilter = DBObjectSearch::FromSibuSQL($this->m_sFilterExpr, $aArgs); + if (!$oFilter) return false; + + if (empty($this->m_sValueAttCode)) + { + $this->m_sValueAttCode = MetaModel::GetNameAttributeCode($oFilter->GetClass()); + } + $oObjects = new DBObjectSet($oFilter, $this->m_aOrderBy); + while ($oObject = $oObjects->Fetch()) + { + $this->m_aValues[$oObject->GetKey()] = $oObject->GetAsHTML($this->m_sValueAttCode); + } + return true; + } + + public function GetValuesDescription() + { + return 'Filter: '.$this->m_sFilterExpr; + } +} + + +/** + * Set of existing values for an attribute, given a search filter and a relation id + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class ValueSetRelatedObjects extends ValueSetObjects +{ + public function __construct($sFilterExp, $sRelCode, $sClass, $sValueAttCode = '', $aOrderBy = array()) + { + $sFullFilterExp = "$sClass: RELATED ($sRelCode, 1) TO ($sFilterExp)"; + parent::__construct($sFullFilterExp, $sValueAttCode, $aOrderBy); + } +} + + +/** + * Set oof existing values for an attribute, given a set of objects (AttributeLinkedSet) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class ValueSetRelatedObjectsFromLinkedSet extends ValueSetDefinition +{ + protected $m_sLinkedSetAttCode; + protected $m_sRelCode; + protected $m_sValueAttCode; + protected $m_aOrderBy; + + public function __construct($sLinkedSetAttCode, $sRelCode, $sValueAttCode = '', $aOrderBy = array()) + { + $this->m_sLinkedSetAttCode = $sLinkedSetAttCode; + $this->m_sRelCode = $sRelCode; + $this->m_sValueAttCode = $sValueAttCode; + $this->m_aOrderBy = $aOrderBy; + } + + protected function LoadValues($aArgs) + { + $this->m_aValues = array(); + + if (empty($this->m_sValueAttCode)) + { + $this->m_sValueAttCode = MetaModel::GetNameAttributeCode($oFilter->GetClass()); + } + + $oCurrentObject = @$aArgs['*this*']; + if (!is_object($oCurrentObject)) return false; + + $oObjects = $oCurrentObject->Get($this->m_sLinkedSetAttCode); + while ($oObject = $oObjects->Fetch()) + { + $this->m_aValues[$oObject->GetKey()] = $oObject->Get($this->m_sValueAttCode); + } + return true; + } + + public function GetValuesDescription() + { + return 'Objects related ('.$this->m_sRelCode.') to objects linked through '.$this->m_sLinkedSetAttCode; + } +} + + +/** + * Fixed set values (could be hardcoded in the business model) + * + * @package iTopORM + * @author Romain Quetiez + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.itop.com + * @since 1.0 + * @version $itopversion$ + */ +class ValueSetEnum extends ValueSetDefinition +{ + public function __construct($Values) + { + if (is_array($Values)) + { + $aValues = $Values; + } + else + { + $aValues = array(); + foreach (explode(",", $Values) as $sVal) + { + $sVal = trim($sVal); + $sKey = $sVal; + $aValues[$sKey] = $sVal; + } + } + $this->m_aValues = $aValues; + } + + protected function LoadValues($aArgs) + { + return true; + } +} + +?> diff --git a/css/blue_green.css b/css/blue_green.css new file mode 100644 index 000000000..1e51162c3 --- /dev/null +++ b/css/blue_green.css @@ -0,0 +1,222 @@ +/* CSS Document */ +body { + font-family: Verdana, Arial, Helevtica; + font-size: smaller; + background-color: #68a; + color:#000000; + margin: 0; /* Remove body margin/padding */ + padding: 0; + overflow: hidden; /* Remove scroll bars on browser window */ +} + +table { + border: 1px solid #000000; +} + +.raw_output { + font-family: Courier-New, Courier, Arial, Helevtica; + font-size: smaller; + background-color: #eeeeee; + color: #000000; + border: 1px dashed #000000; + padding: 0.25em; + margin-top: 1em; +} + +th { + font-family: Verdana, Arial, Helvetica; + font-size: smaller; + color: #000000; + background-color:#ace27d; +} + +td { + font-family: Verdana, Arial, Helvetica; + font-size: smaller; + background-color: #b7cfe8; +} + +tr.clicked td { + font-family: Verdana, Arial, Helvetica; + font-size: smaller; + background-color: #ffcfe8; +} + +td.label { + font-family: Verdana, Arial, Helvetica; + font-size: smaller; + color: #000000; + background-color:#ace27d; + padding: 0.2em; +} + +td a, td a:visited { + text-decoration:none; + color:#000000; +} +td a:hover { + text-decoration:underline; + color:#FFFFFF; +} + +a.small_action { + font-family: Verdana, Arial, Helvetica; + font-size: smaller; + color: #000000; + text-decoration:none; +} + +.display_block { + noborder: 1px dashed #CCC; + background: #79b; + padding:0.25em; +} +div#TopPane .display_block { + background: #f0eee0; + padding:0.25em; + text-align:center; +} +div#TopPane label { + color:#000; + background: #f0eee0; +} + +div#TopPane td { + color:#000; + background: #f0eee0; +} + +.loading { + noborder: 1px dashed #CCC; + background: #b9c1c8; + padding:0.25em; +} + +label { + font-family:Georgia, "Times New Roman", Times, serif; + color:#FFFFFF; + text-align:right; +} + +input.textSearch { + border:1px solid #333; + noheight:1.2em; + font-size:0.8em; + font-family:Verdana, Arial, Helvetica, sans-serif; + color:#000000; +} + +/* By Rom */ +.csvimport_createobj { + color: #AA0000; + background-color:#EEEEEE; +} +.csvimport_error { + font-weight: bold; + color: #FF0000; + background-color:#EEEEEE; +} +.csvimport_warning { + color: #CC8888; + background-color:#EEEEEE; +} +.csvimport_ok { + color: #00000; + background-color:#BBFFBB; +} +.csvimport_reconkey { + font-style: italic; + color: #888888; + background-color:#FFFFF; +} +.csvimport_extreconkey { + color: #888888; + background-color:#FFFFFF; +} + +.treeview, .treeview ul { + padding: 0; + margin: 0; + list-style: none; +} + +.treeview li { + margin: 0; + padding: 3px 0pt 3px 16px; + font-size:0.9em; +} + +ul.dir li { + padding: 2px 0 0 16px; +} + +.treeview li { background: url(../images/tv-item.gif) 0 0 no-repeat; } +.treeview .collapsable { background-image: url(/images/tv-collapsable.gif); } +.treeview .expandable { background-image: url(/images/tv-expandable.gif); } +.treeview .last { background-image: url(/images/tv-item-last.gif); } +.treeview .lastCollapsable { background-image: url(/images/tv-collapsable-last.gif); } +.treeview .lastExpandable { background-image: url(/images/tv-expandable-last.gif); } + +#Header { padding: 0; background:#ccc url(/images/bandeau2.gif) repeat-x center;} +div.iTopLogo { + background:url(/images/iTop.gif) no-repeat center; + width:100px; + height:56px; +} +div.iTopLogo span { + display:none; +} + +#MySplitter { + /* Height is set to match window size in $().ready() below */ + border:0px; + margin:4px; + padding:0px; + min-width: 100px; /* Splitter can't be too thin ... */ + min-height: 100px; /* ... or too flat */ +} +#LeftPane { + background: #f0eee0; + padding: 4px; + overflow: auto; /* Scroll bars appear as needed */ + color:#666; +} +#TopPane { /* Top nested in right pane */ + background: #f0eee0; + padding: 4px; + height: 150px; /* Initial height */ + min-height: 75px; /* Minimum height */ + overflow: auto; + color:#666; +} +#RightPane { /* Bottom nested in right pane */ + background: #79b; + height:150px; /* Initial height */ + min-height:130px; + no.padding:15px; + no.margin:10px; + overflow:auto; + color:#fff; +} + +#BottomPane { /* Bottom nested in right pane */ + background: #79b; + padding: 4px; + overflow: auto; + color:#fff; +} +#MySplitter .vsplitbar { + width: 7px; + height: 50px; + background: #68a url(/images/vgrabber2.gif) no-repeat center; +} +#MySplitter .vsplitbar.active, #MySplitter .vsplitbar:hover { + background: #68a url(/images/vgrabber2_active.gif) no-repeat center; +} +#MySplitter .hsplitbar { + height: 8px; + background: #68a url(/images/hgrabber2.gif) no-repeat center; +} +#MySplitter .hsplitbar.active, #MySplitter .hsplitbar:hover { + background: #68a url(/images/hgrabber2_active.gif) no-repeat center; +} diff --git a/css/date.picker.css b/css/date.picker.css new file mode 100644 index 000000000..a394482a0 --- /dev/null +++ b/css/date.picker.css @@ -0,0 +1,117 @@ + + +table.jCalendar { + border: 1px solid #000; + background: #aaa; + border-collapse: separate; + border-spacing: 2px; +} +table.jCalendar th { + background: #333; + color: #fff; + font-weight: bold; + padding: 3px 5px; +} +table.jCalendar td { + background: #ccc; + color: #000; + padding: 3px 5px; + text-align: center; +} +table.jCalendar td.other-month { + background: #ddd; + color: #aaa; +} +table.jCalendar td.today { + background: #666; + color: #fff; +} +table.jCalendar td.selected { + background: #f66; + color: #fff; +} +table.jCalendar td.selected:hover { + background: #f33; + color: #fff; +} +table.jCalendar td:hover, table.jCalendar td.dp-hover { + background: #fff; + color: #000; +} +table.jCalendar td.disabled, table.jCalendar td.disabled:hover { + background: #bbb; + color: #888; +} + +/* For the popup */ + +/* NOTE - you will probably want to style a.dp-choose-date - see how I did it in demo.css */ + +div.dp-popup { + position: relative; + background: #ccc; + font-size: 10px; + font-family: arial, sans-serif; + padding: 2px; + width: 171px; + line-height: 1.2em; +} +div#dp-popup { + position: absolute; + z-index: 199; +} +div.dp-popup h2 { + font-size: 12px; + text-align: center; + margin: 2px 0; + padding: 0; +} +a#dp-close { + font-size: 11px; + padding: 4px 0; + text-align: center; + display: block; +} +a#dp-close:hover { + text-decoration: underline; +} +div.dp-popup a { + color: #000; + text-decoration: none; + padding: 3px 2px 0; +} +div.dp-popup div.dp-nav-prev { + position: absolute; + top: 2px; + left: 4px; + width: 100px; +} +div.dp-popup div.dp-nav-prev a { + float: left; +} +/* Opera needs the rules to be this specific otherwise it doesn't change the cursor back to pointer after you have disabled and re-enabled a link */ +div.dp-popup div.dp-nav-prev a, div.dp-popup div.dp-nav-next a { + cursor: pointer; +} +div.dp-popup div.dp-nav-prev a.disabled, div.dp-popup div.dp-nav-next a.disabled { + cursor: default; +} +div.dp-popup div.dp-nav-next { + position: absolute; + top: 2px; + right: 4px; + width: 100px; +} +div.dp-popup div.dp-nav-next a { + float: right; +} +div.dp-popup a.disabled { + cursor: default; + color: #aaa; +} +div.dp-popup td { + cursor: pointer; +} +div.dp-popup td.disabled { + cursor: default; +} \ No newline at end of file diff --git a/css/default.css b/css/default.css new file mode 100644 index 000000000..eaabed838 --- /dev/null +++ b/css/default.css @@ -0,0 +1,165 @@ +/* CSS Document */ +body { + font-family: Verdana, Arial, Helevtica; + font-size: smaller; + background-color: #ffffff; + color:#000000; + margin: 0; /* Remove body margin/padding */ + padding: 0; + overflow: hidden; /* Remove scroll bars on browser window */ +} + +table { + border: 1px solid #000000; +} + +.raw_output { + font-family: Courier-New, Courier, Arial, Helevtica; + font-size: smaller; + background-color: #eeeeee; + color: #000000; + border: 1px dashed #000000; + padding: 0.25em; + margin-top: 1em; +} + +th { + font-family: Verdana, Arial, Helevtica; + font-size: smaller; + color: #000000; + background-color:#E1DEB5; +} + +td { + font-family: Verdana, Arial, Helevtica; + font-size: smaller; +} + +td.label { + font-family: Verdana, Arial, Helevtica; + font-size: smaller; + color: #000000; + background-color:#E1DEB5; + padding: 0.2em; +} + +a.small_action { + font-family: Verdana, Arial, Helvetica; + font-size: smaller; + color: #000000; + text-decoration:none; +} + +.display_block { + border: 1px dashed #CCC; + background: #CFC; + padding:0.25em; +} + +.loading { + border: 1px dashed #CCC; + background: #FCC; + padding:0.25em; +} + +/* By Rom */ +.csvimport_createobj { + color: #AA0000; + background-color:#EEEEEE; +} +.csvimport_error { + font-weight: bold; + color: #FF0000; + background-color:#EEEEEE; +} +.csvimport_warning { + color: #CC8888; + background-color:#EEEEEE; +} +.csvimport_ok { + color: #00000; + background-color:#BBFFBB; +} +.csvimport_reconkey { + font-style: italic; + color: #888888; + background-color:#FFFFF; +} +.csvimport_extreconkey { + color: #888888; + background-color:#FFFFFF; +} + +.treeview, .treeview ul { + padding: 0; + margin: 0; + list-style: none; +} + +.treeview li { + margin: 0; + padding: 3px 0pt 3px 16px; +} + +ul.dir li { padding: 2px 0 0 16px; } + +.treeview li { background: url(../images/tv-item.gif) 0 0 no-repeat; } +.treeview .collapsable { background-image: url(../images/tv-collapsable.gif); } +.treeview .expandable { background-image: url(../images/tv-expandable.gif); } +.treeview .last { background-image: url(../images/tv-item-last.gif); } +.treeview .lastCollapsable { background-image: url(../images/tv-collapsable-last.gif); } +.treeview .lastExpandable { background-image: url(../images/tv-expandable-last.gif); } + +#MySplitter { + /* Height is set to match window size in $().ready() below */ + border:0px; + margin:4px; + padding:0px; + min-width: 100px; /* Splitter can't be too thin ... */ + min-height: 100px; /* ... or too flat */ +} +#LeftPane { + background: #f0eee0; + padding: 4px; + overflow: auto; /* Scroll bars appear as needed */ + color:#666; +} +#TopPane { /* Top nested in right pane */ + background: #f0eee0; + padding: 4px; + height: 150px; /* Initial height */ + min-height: 75px; /* Minimum height */ + overflow: auto; + color:#666; +} +#RightPane { /* Bottom nested in right pane */ + background: #79b; + height:150px; /* Initial height */ + min-height:130px; + no.padding:15px; + no.margin:10px; + overflow:auto; + color:#fff; +} + +#BottomPane { /* Bottom nested in right pane */ + background: #79b; + padding: 4px; + overflow: auto; + color:#fff; +} +#MySplitter .vsplitbar { + width: 7px; + height: 50px; + background: #68a url(../images/vgrabber2.gif) no-repeat center; +} +#MySplitter .vsplitbar.active, #MySplitter .vsplitbar:hover { + background: #68a url(../images/vgrabber2_active.gif) no-repeat center; +} +#MySplitter .hsplitbar { + height: 8px; + background: #68a url(../images/hgrabber2.gif) no-repeat center; +} +#MySplitter .hsplitbar.active, #MySplitter .hsplitbar:hover { + background: #68a url(../images/hgrabber2_active.gif) no-repeat center; +} diff --git a/css/jqModal.css b/css/jqModal.css new file mode 100644 index 000000000..db45b7039 --- /dev/null +++ b/css/jqModal.css @@ -0,0 +1,40 @@ +/* jqModal base Styling courtesy of; + Brice Burgess */ + +/* The Window's CSS z-index value is respected (takes priority). If none is supplied, + the Window's z-index value will be set to 3000 by default (in jqModal.js). You + can change this value by either; + a) supplying one via CSS + b) passing the "zIndex" parameter. E.g. (window).jqm({zIndex: 500}); */ + +.jqmWindow { + display: none; + + position: fixed; + top: 10%; + left: 20%; + + margin-left: -100px; + width: 800px; + + background-color: #FFF; + color: #333; + border: 1px solid black; + padding: 12px; +} + +.jqmOverlay { background-color: #333; } + +/* Background iframe styling for IE6. Prevents ActiveX bleed-through (" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
" ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and \n"); + } + break; + + case 'apply_modify': + $sClass = utils::ReadPostedParam('class', ''); + $id = utils::ReadPostedParam('id', ''); + $sTransactionId = utils::ReadPostedParam('transaction_id', ''); + if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid ! + { + $oP->add("

'class' and 'id' parameters must be specifed for this operation.

\n"); + } + else if (!utils::IsTransactionValid($sTransactionId)) + { + $oP->p("Error: object has already be updated!\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $id); + if ($oObj != null) + { + $oP->set_title("iTop - ".$oObj->GetName()." - $sClass modification"); + $oP->add("

".$oObj->GetName()." - $sClass modification

\n"); + $bObjectModified = false; + foreach(MetaModel::ListAttributeDefs(get_class($oObj)) as $sAttCode=>$oAttDef) + { + $iFlags = $oObj->GetAttributeFlags($sAttCode); + if ($iFlags & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) + { + // Non-visible, or read-only attribute, do nothing + } + else if ($oAttDef->IsLinkSet()) + { + // Link set, the data is a set of link objects, encoded in JSON + $aAttributes[$sAttCode] = trim(utils::ReadPostedParam("attr_$sAttCode", '')); + if (!empty($aAttributes[$sAttCode])) + { + $oLinkSet = WizardHelper::ParseJsonSet($oObj, $oAttDef->GetLinkedClass(), $oAttDef->GetExtKeyToMe(), $aAttributes[$sAttCode]); + $oObj->Set($sAttCode, $oLinkSet); + // TO DO: detect a real modification, for now always update !! + $bObjectModified = true; + } + } + else if (!$oAttDef->IsExternalField()) + { + $aAttributes[$sAttCode] = trim(utils::ReadPostedParam("attr_$sAttCode", '')); + $previousValue = $oObj->Get($sAttCode); + if (!empty($aAttributes[$sAttCode]) && ($previousValue != $aAttributes[$sAttCode])) + { + $oObj->Set($sAttCode, $aAttributes[$sAttCode]); + $bObjectModified = true; + } + } + } + if (!$bObjectModified) + { + $oP->p("No modification detected. ".get_class($oObj)." has not been updated.\n"); + } + else if ($oObj->CheckToUpdate()) + { + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + if (UserRights::GetUser() != UserRights::GetRealUser()) + { + $sUserString = UserRights::GetRealUser()." on behalf of ".UserRights::GetUser(); + } + else + { + $sUserString = UserRights::GetUser(); + } + $oMyChange->Set("userinfo", $sUserString); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBUpdateTracked($oMyChange); + + $oP->p(get_class($oObj)." updated.\n"); + } + else + { + $oP->p("Error: object can not be updated!\n"); + //$oObj->Reload(); // restore default values! + } + } + else + { + $oP->set_title("iTop - Error"); + $oP->add("

Sorry this object does not exist (or you are not allowed to edit it).

\n"); + } + } + $oObj->DisplayDetails($oP); + break; + + case 'delete': + $sClass = utils::ReadParam('class', ''); + $id = utils::ReadParam('id', ''); + $oObj = $oContext->GetObject($sClass, $id); + $sName = $oObj->GetName(); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + if (UserRights::GetUser() != UserRights::GetRealUser()) + { + $sUserString = UserRights::GetRealUser()." on behalf of ".UserRights::GetUser(); + } + else + { + $sUserString = UserRights::GetUser(); + } + $oMyChange->Set("userinfo", $sUserString); + $oMyChange->DBInsert(); + $oObj->DBDeleteTracked($oMyChange); + $oP->add("

".$sName." - $sClass deleted

\n"); + break; + + case 'apply_new': + $oP->p('Creation of the object'); + $oP->p('Obsolete, should now go through the wizard...'); + break; + + case 'apply_clone': + $sClass = utils::ReadPostedParam('class', ''); + $iCloneId = utils::ReadPostedParam('clone_id', ''); + $sTransactionId = utils::ReadPostedParam('transaction_id', ''); + if (!utils::IsTransactionValid($sTransactionId)) + { + $oP->p("Error: object has already be cloned!\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $iCloneId); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + if (UserRights::GetUser() != UserRights::GetRealUser()) + { + $sUserString = UserRights::GetRealUser()." on behalf of ".UserRights::GetUser(); + } + else + { + $sUserString = UserRights::GetUser(); + } + $oMyChange->Set("userinfo", $sUserString); + $iChangeId = $oMyChange->DBInsert(); + $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($oObj)); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + { + if ( ('finalclass' != $sAttCode) && // finalclass is a reserved word, hardcoded ! + ($sStateAttCode != $sAttCode) && + (!$oAttDef->IsExternalField()) ) + { + $value = utils::ReadPostedParam('attr_'.$sAttCode, ''); + $oObj->Set($sAttCode, $value); + } + } + $oObj->DBCloneTracked($oMyChange); + $oP->add("

".$oObj->GetName()." - $sClass created

\n"); + $oObj->DisplayDetails($oP); + } + + break; + + case 'wizard_apply_new': + $sJson = utils::ReadPostedParam('json_obj', ''); + $oWizardHelper = WizardHelper::FromJSON($sJson); + $sTransactionId = utils::ReadPostedParam('transaction_id', ''); + if (!utils::IsTransactionValid($sTransactionId)) + { + $oP->p("Error: object has already be created!\n"); + } + else + { + $oObj = $oWizardHelper->GetTargetObject(); + if (is_object($oObj)) + { + $sClass = get_class($oObj); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + if (UserRights::GetUser() != UserRights::GetRealUser()) + { + $sUserString = UserRights::GetRealUser()." on behalf of ".UserRights::GetUser(); + } + else + { + $sUserString = UserRights::GetUser(); + } + $oMyChange->Set("userinfo", $sUserString); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBInsertTracked($oMyChange); + $oP->set_title("iTop - ".$oObj->GetName()." - $sClass created"); + $oP->add("

".$oObj->GetName()." - $sClass created

\n"); + $oObj->DisplayDetails($oP); + } + } + break; + + case 'stimulus': + $sClass = utils::ReadParam('class', ''); + $id = utils::ReadParam('id', ''); + $sStimulus = utils::ReadParam('stimulus', ''); + if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid ! + { + $oP->add("

'class', 'id' and 'stimulus' parameters must be specifed for this operation.

\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $id); + if ($oObj != null) + { + $aTransitions = $oObj->EnumTransitions(); + $aStimuli = MetaModel::EnumStimuli($sClass); + if (!isset($aTransitions[$sStimulus])) + { + $oP->add("

Error: Invalid stimulus: '$sStimulus' on object: {$oObj->GetName()} in state {$oObj->GetState()}.

\n"); + } + else + { + $sActionLabel = $aStimuli[$sStimulus]->Get('label'); + $sActionDetails = $aStimuli[$sStimulus]->Get('description'); + $aTransition = $aTransitions[$sStimulus]; + $sTargetState = $aTransition['target_state']; + $aTargetStates = MetaModel::EnumStates($sClass); + $oP->add("
\n"); + $oP->add("

$sActionLabel - {$oObj->GetName()}

\n"); + //$oP->add("

Applying '$sActionLabel' on object: {$oObj->GetName()} in state {$oObj->GetState()} to target state: $sTargetState.

\n"); + $oP->add("
\n"); + $oObj->DisplayBareDetails($oP); + $aTargetState = $aTargetStates[$sTargetState]; + //print_r($aTransitions[$sStimulus]); + //print_r($aTargetState); + $aExpectedAttributes = $aTargetState['attribute_list']; + $oP->add("
\n"); + $oP->add("

$sActionDetails

\n"); + $oP->add("
\n"); + $oP->add("
\n"); + $aDetails = array(); + foreach($aExpectedAttributes as $sAttCode => $iExpectCode) + { + // Prompt for an attribute if + // - the attribute must be changed or must be displayed to the user for confirmation + // - or the field is mandatory and currently empty + if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) || + (($iExpectCode & OPT_ATT_MANDATORY) && ($oObj->Get($sAttCode) == '')) ) + { + $aAttributesDef = MetaModel::ListAttributeDefs($sClass); + $oAttDef = $aAttributesDef[$sAttCode]; + $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $oObj->Get($sAttCode), $oObj->GetDisplayValue($sAttCode)); + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue); + } + } + $oP->details($aDetails); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add($oAppContext->GetForForm()); + $oP->add("    \n"); + $oP->add("\n"); + $oP->add("
\n"); + $oP->add("
\n"); + $oP->add("
\n"); + } + } + else + { + $oP->set_title("iTop - Error"); + $oP->add("

Sorry this object does not exist (or you are not allowed to edit it).

\n"); + } + } + break; + + case 'apply_stimulus': + $sClass = utils::ReadPostedParam('class', ''); + $id = utils::ReadPostedParam('id', ''); + $sTransactionId = utils::ReadPostedParam('transaction_id', ''); + $sStimulus = utils::ReadPostedParam('stimulus', ''); + if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid ! + { + $oP->add("

'class', 'id' and 'stimulus' parameters must be specifed for this operation.

\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $id); + if ($oObj != null) + { + $aTransitions = $oObj->EnumTransitions(); + $aStimuli = MetaModel::EnumStimuli($sClass); + if (!isset($aTransitions[$sStimulus])) + { + $oP->add("

Error: Invalid stimulus: '$sStimulus' on object: {$oObj->GetName()} in state {$oObj->GetState()}.

\n"); + } + else if (!utils::IsTransactionValid($sTransactionId)) + { + $oP->p("Error: object has already be updated!\n"); + } + else + { + $sActionLabel = $aStimuli[$sStimulus]->Get('label'); + $sActionDetails = $aStimuli[$sStimulus]->Get('description'); + $aTransition = $aTransitions[$sStimulus]; + $sTargetState = $aTransition['target_state']; + $aTargetStates = MetaModel::EnumStates($sClass); + $oP->add("
\n"); + $oP->add("

$sActionLabel - {$oObj->GetName()}

\n"); + $oP->add("

$sActionDetails

\n"); + $oP->add("

Applying '$sActionLabel' on object: {$oObj->GetName()} in state {$oObj->GetState()} to target state: $sTargetState.

\n"); + $oP->add("
\n"); + $aTargetState = $aTargetStates[$sTargetState]; + //print_r($aTransitions[$sStimulus]); + //print_r($aTargetState); + $aExpectedAttributes = $aTargetState['attribute_list']; + $aDetails = array(); + foreach($aExpectedAttributes as $sAttCode => $iExpectCode) + { + if (($iExpectCode & OPT_ATT_MUSTCHANGE) || ($oObj->Get($sAttCode) == '') ) + { + $paramValue = utils::ReadPostedParam("attr_$sAttCode", ''); + $oObj->Set($sAttCode, $paramValue); + } + } + if ($oObj->ApplyStimulus($sStimulus) && $oObj->CheckToUpdate()) + { + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + if (UserRights::GetUser() != UserRights::GetRealUser()) + { + $sUserString = UserRights::GetRealUser()." on behalf of ".UserRights::GetUser(); + } + else + { + $sUserString = UserRights::GetUser(); + } + $oMyChange->Set("userinfo", $sUserString); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBUpdateTracked($oMyChange); + + $oP->p(get_class($oObj)." updated.\n"); + } + $oObj->DisplayDetails($oP); + } + } + else + { + $oP->set_title("iTop - Error"); + $oP->add("

Sorry this object does not exist (or you are not allowed to edit it).

\n"); + } + } + break; + + + default: + $oActiveNode->RenderContent($oP, $oAppContext->GetAsHash()); +} +$oP->output(); +?> diff --git a/pages/UniversalSearch.php b/pages/UniversalSearch.php new file mode 100644 index 000000000..ebe762fb3 --- /dev/null +++ b/pages/UniversalSearch.php @@ -0,0 +1,142 @@ +add("
"); +$oP->add("
"); +$oP->add(""); +$oP->add("Select the class to search:
"); + +// Second part: advanced search form: +$oFilter = null; +if (!empty($sFilter)) +{ + $oFilter = CMDBSearchFilter::unserialize($sFilter); +} +else if (!empty($sClassName)) +{ + $oFilter = new CMDBSearchFilter($sClassName); +} + +if ($oFilter != null) +{ + $oSet =new CMDBObjectSet($oFilter); + cmdbAbstractObject::DisplaySearchForm($oP, $oSet, array('org_id' => $currentOrganization, 'class' => $sClassName)); + $oP->add("
\n"); + + // Search results + $oP->add("
"); + $oResultBlock = new DisplayBlock($oFilter, 'list', false); + $oResultBlock->RenderContent($oP); + + // Menu node + $sFilter = $oFilter->ToSibusQL(); + $sMenuNodeContent = << +$sFilter +
+
+

+$sFilter +
+EOF; + + + if ($sOperation == "add_menu") + { + $oMenuNode = MetaModel::NewObject('menuNode'); + $sClass = utils::ReadPostedParam('class', ''); + $sLabel = utils::ReadPostedParam('label', ''); + $sDescription = utils::ReadPostedParam('description', ''); + $iPreviousNodeId = utils::ReadPostedParam('previous_node_id', 1); + $bChildItem = utils::ReadPostedParam('child_item', false); + $oMenuNode->Set('label', $sDescription); + $oMenuNode->Set('name', $sLabel); + $oMenuNode->Set('icon_path', '/images/std_view.gif'); + $oMenuNode->Set('template', $sMenuNodeContent); + $oMenuNode->Set('hyperlink', 'UI.php'); + $oMenuNode->Set('type', 'user'); + $oMenuNode->Set('user_id', UserRights::GetUserId()); + $oPreviousNode = MetaModel::GetObject('menuNode', $iPreviousNodeId); + if ($bChildItem) + { + // Insert the new item as a child of the previous one + $oMenuNode->Set('parent_id', $iPreviousNodeId); + $oMenuNode->Set('rank', 1); // A new child item is the first one, so let's start the numbering at 1 + // If there are already child nodes, shift their rank by one + // to make room for the newly inserted child node + $oNextNodeSet = $oPreviousNode->GetChildNodesSet(null); // null => don't limit ourselves to the user context + // since we need to update all children in order to keep + // the database consistent + while($oNextNode = $oNextNodeSet->Fetch()) + { + $oNextNode->Set('rank', 1 + $oNextNode->Get('rank')); + $oNextNode->DBUpdate(); + } + } + else + { + // Insert the new item as the next sibling of the previous one + $oMenuNode->Set('parent_id', $oPreviousNode->Get('parent_id')); + $oMenuNode->Set('rank', 1 + $oPreviousNode->Get('rank')); // the new item comes immediatly after the selected one + // Add 1 to the rank of all the nodes currently following the 'selected' one + // to make room for the newly inserted node + $oNextNodeSet = $oPreviousNode->GetNextNodesSet(null); // null => don't limit ourselves to the user context + // since we need to update all children in order to keep + // the database consistent + while($oNextNode = $oNextNodeSet->Fetch()) + { + $oNextNode->Set('rank', 1 + $oNextNode->Get('rank')); + $oNextNode->DBUpdate(); + } + + } + if ($oMenuNode->CheckToInsert()) + { + $oMenuNode->DBInsert(); + $oP->add("
"); + $oP->add("

Menu item created !

"); + $oP->add(""); + $oP->add(""); + $oP->add(""); + $oP->add(""); + } + } + + $oP->add("\n"); +} +else +{ + $oP->add("\n"); +} + +$oP->output(); +?> diff --git a/pages/advanced_search.php b/pages/advanced_search.php new file mode 100644 index 000000000..e10a2c095 --- /dev/null +++ b/pages/advanced_search.php @@ -0,0 +1,310 @@ +no_cache(); + + +MetaModel::CheckDefinitions(); +// new API - MetaModel::DBCheckFormat(); +// not necessary, and time consuming! +// MetaModel::DBCheckIntegrity(); + + +function ReadParam($sName, $defaultValue = "") +{ + return isset($_REQUEST[$sName]) ? $_REQUEST[$sName] : $defaultValue; +} + + + +function Page1_AskClass($oPage) +{ + $oPage->add("\n"); + //$oPage->add(""); + $oPage->p("Please select the type of object that you want to look for:"); + $oPage->MakeClassesSelect("class", "", 50); + $oPage->add("\n"); + $oPage->add("
\n"); +} + + +function Page2_ConfigFilters($oPage, $oFilter) +{ + $sClass = $oFilter->GetClass(); + + $oPage->p("Objects of class $sClass"); + $oPage->add("
\n"); + $oPage->add("\n"); + + // Full text input + // + $oPage->add("
\n"); + $oPage->add("Full text: "); + $sFullText = ""; + foreach($oFilter->GetCriteria_FullText() as $sFullText) + { + // #@# Known limitation: do not consider other full text conditions... + continue; + } + + $oPage->add("\n"); + $oPage->add("
\n"); + + // Attribute-related criteria + // + foreach (MetaModel::GetClassFilterDefs($sClass) as $sFltCode => $oFltDef) + { + // Set its current values + $sOpCode = "__none__"; + $sValue = ""; + foreach($oFilter->GetCriteria() as $aCritInfo) + { + if ($aCritInfo["filtercode"] == "pkey") + { + // ??? + } + elseif ($aCritInfo["filtercode"] == $sFltCode) + { + $sOpCode = $aCritInfo["opcode"]; + $sValue = $aCritInfo["value"]; + break; + } + } + + $oPage->add("
\n"); + //$oPage->add($oFltDef->GetType()." (".$oFltDef->GetTypeDesc().")"); + $oPage->add(" ".$oFltDef->GetLabel()." "); + + $aOperators = array_merge(array("__none__" => ""), $oFltDef->GetOperators()); + $oPage->add_select($aOperators, "flt_ops[$sFltCode]", $sOpCode, 100); + $oPage->add("\n"); + + $oPage->add("\n"); + $oPage->add("
\n"); + } + + // Ext key criteria + // + foreach (MetaModel::EnumReferencedClasses($sClass) as $sExtKeyAttCode => $sRemoteClass) + { + // Set its current values + $oSubFilter = $oFilter->GetCriteria_PointingTo($sExtKeyAttCode); + if (!$oSubFilter) + { + $oSubFilter = new CMDBSearchFilter($sRemoteClass); + } + + $oPage->add("
\n"); + $oAtt = MetaModel::GetAttributeDef($oFilter->GetClass(), $sExtKeyAttCode); + $oPage->add($oAtt->GetLabel()." having ({$oSubFilter->DescribeConditions()})"); + //$oPage->add("having $oFilter->DescribeConditionPointTo($sExtKeyAttCode)); + $oPage->add("\n"); + + $oPage->add(dialogstack::RenderEditableField("Edit...", "flt_pointto[$sExtKeyAttCode]", $oSubFilter->serialize(), true)); + $oPage->add("
\n"); + } + + // Ext key criteria, the other way + // + foreach (MetaModel::EnumReferencingClasses($sClass, true) as $sRemoteClass => $aRemoteKeys) + { + foreach ($aRemoteKeys as $sExtKeyAttCode) + { + // Set its current values + $oSubFilter = $oFilter->GetCriteria_ReferencedBy($sRemoteClass, $sExtKeyAttCode); + if (!$oSubFilter) + { + $oSubFilter = new CMDBSearchFilter($sRemoteClass); + } + + $oPage->add("
\n"); + //$oPage->add($oFilter->DescribeConditionRefBy($sRemoteClass, $sExtKeyAttCode)); + $oAtt = MetaModel::GetAttributeDef($sRemoteClass, $sExtKeyAttCode); + $oPage->add("being ".$oAtt->GetLabel()." for ".$sRemoteClass."(e)s in ({$oSubFilter->DescribeConditions()})"); + $oPage->add("\n"); + + $oPage->add(dialogstack::RenderEditableField("Edit...", "flt_refedby[$sRemoteClass][$sExtKeyAttCode]", $oSubFilter->serialize(), true)); + $oPage->add("
\n"); + } + } + + // Ext key criteria -> link objects + // + foreach (MetaModel::EnumLinkingClasses($sClass) as $sLinkClass => $aRemoteClasses) + { + foreach($aRemoteClasses as $sExtKeyAttCode => $sRemoteClass) + { + // Set its current values + //$oSubFilter = $oFilter->GetCriteria_PointingTo($sExtKeyAttCode); + $oSubFilter = null; + if (!$oSubFilter) + { + $oSubFilter = new CMDBSearchFilter($sRemoteClass); + } + $oPage->add("
\n"); + //$oPage->add(" ".MetaModel::GetClassLabel($sRemoteClass)." "); + $oPage->add(" Linked to '".MetaModel::GetLinkLabel($sLinkClass, $sExtKeyAttCode)."' by "); + $oSubFilter = new CMDBSearchFilter($sRemoteClass); + $oPage->add($oSubFilter->__DescribeHTML()); + $oPage->add("\n"); + + $oPage->add(dialogstack::RenderEditableField("Edit...", "flt_linkedwith[$sRemoteClass][$sExtKeyAttCode]", $oSubFilter->serialize(), true)); + $oPage->add("
\n"); + } + } + + $oPage->add("\n"); + $oPage->add("
\n"); +} + +function MakeFilterFromArgs() +{ + $sClass = ReadParam("class"); + $sFilterFullText = ReadParam("flt_fulltext", ""); + $aFilterOps = ReadParam("flt_ops", array()); + $aFilterValues = ReadParam("flt_values", array()); + $aPointTo = ReadParam("flt_pointto", array()); + $aRefedBy = ReadParam("flt_refedby", array()); + $aLinkedWith = ReadParam("flt_linkedwith", array()); + + $oFilter = new CMDBSearchFilter($sClass); + + if (!empty($sFilterFullText)) + { + $oFilter->AddCondition_FullText($sFilterFullText); + } + + foreach($aFilterOps as $sFltCode=>$sOpCode) + { + if ($sOpCode == "__none__") continue; + $oFilter->AddCondition($sFltCode, $aFilterValues[$sFltCode], $sOpCode); + } + + foreach($aPointTo as $sExtKeyAttCode=>$sFilterShortcut) + { + $oSubFilter = CMDBSearchFilter::unserialize($sFilterShortcut); + $oFilter->AddCondition_PointingTo($oSubFilter, $sExtKeyAttCode); + } + + foreach($aRefedBy as $sForeignClass=>$aExtKeys) + { + foreach($aExtKeys as $sForeignExtKey=>$sFilterShortcut) + { + //MyHelpers::var_dump_html("$sForeignClass / $sForeignExtKey / $sFilterShortcut"); + $oSubFilter = CMDBSearchFilter::unserialize($sFilterShortcut); + //MyHelpers::var_dump_html($oSubFilter); + $oFilter->AddCondition_ReferencedBy($oSubFilter, $sForeignExtKey); + } + } + +// $oFilter->AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget); + + return $oFilter; +} + +function Page3_ViewResults($oPage, $oFilter) +{ + // Output results in various forms... + // + if ($oFilter->IsAny()) + { + $oPage->p("You are considering the ENTIRE set of objects..."); + } + else + { + $oPage->p($oFilter->__DescribeHTML()); + + $oSet = new CMDBObjectSet($oFilter); + $oPage->p("Found ".$oSet->Count()." items"); + + $sFilterPhrase = $oFilter->serialize(); + $oPage->p("See detailed results"); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// M a i n P r o g r a m +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + + +$oPage->p("

Advanced search

"); + + +// Page 1 - Ask class +// +// Page 2 - Class is given, enum existing filters/possible links +// +// Page 3 - Interpret user choices, create a filter and render its string representation +// + +//MyHelpers::arg_dump_html(); +//MyHelpers::var_dump_html($_SESSION); + +if (ReadParam('userconfig', false)) +{ + $sTodo = 'userconfig'; +} +if (ReadParam('makeit', false)) +{ + $sTodo = 'makeit'; +} +else +{ + if (dialogstack::IsDialogStartup()) + { + $sInit = dialogstack::StartDialog(); + $oFilter = CMDBSearchFilter::unserialize($sInit); + $sTodo = 'userconfig'; + } + else + { + $sClass = ReadParam('class', ''); + if (empty($sClass)) + { + $sTodo = 'selectclass'; + } + else + { + $oFilter = MakeFilterFromArgs(); + $sTodo = 'userconfig'; + } + } +} + +switch ($sTodo) +{ +case "selectclass": + Page1_AskClass($oPage); + break; + +case "userconfig": + dialogstack::DeclareCaller("Define filter for ".$oFilter->GetClass()); + $oPage->add(implode(" / ", dialogstack::GetCurrentStack())); + Page2_ConfigFilters($oPage, $oFilter); + break; + +case "makeit": + $oFilter = MakeFilterFromArgs(); + Page3_ViewResults($oPage, $oFilter); + $oPage->add(dialogstack::RenderEndDialogForm(DLGSTACK_OK, "Use filter", $oFilter->serialize())); + $oPage->add(dialogstack::RenderEndDialogForm(DLGSTACK_CANCEL, "Annuler")); + break; + +default: + trigger_error("Wrong value for arg todo ($sTodo)", E_USER_ERROR); +} + +$oPage->output(); + +?> diff --git a/pages/ajax.php b/pages/ajax.php new file mode 100644 index 000000000..1173ddd21 --- /dev/null +++ b/pages/ajax.php @@ -0,0 +1,40 @@ +no_cache(); +$oPage->add("

Asynchronous versus asynchronous DisplayBlocks

\n"); + +$oContext = new UserContext(); +$operation = ReadParam('operation', ''); +$sClassName = ReadParam('class', 'bizContact'); +$sOrganizationCode = ReadParam('org', 'ITOP'); + +$oPage->p("[Synchronous] Count of all $sClassName objects for organization '$sOrganizationCode'"); +$oFilter = $oContext->NewFilter($sClassName); +$oFilter ->AddCondition('organization', $sOrganizationCode, '='); +$oBlock = new DisplayBlock($oFilter, 'count', false); +$oBlock->Display($oPage, "block1"); + +$oPage->p("[Asynchronous] All $sClassName objects for organization '$sOrganizationCode'"); +$oFilter = $oContext->NewFilter($sClassName); +$oFilter ->AddCondition('organization', $sOrganizationCode, '='); +$oBlock = new DisplayBlock($oFilter, 'list', true); +$oBlock->Display($oPage, "block2"); + +$oPage->p("[Asynchronous] Details of all $sClassName objects for organization '$sOrganizationCode'"); +$oFilter = $oContext->NewFilter($sClassName); +$oFilter ->AddCondition('organization', $sOrganizationCode, '='); +$oBlock = new DisplayBlock($oFilter, 'details', true); +$oBlock->Display($oPage, "block3"); + +$oPage->output(); +?> diff --git a/pages/ajax.render.php b/pages/ajax.render.php new file mode 100644 index 000000000..8c3424b5c --- /dev/null +++ b/pages/ajax.render.php @@ -0,0 +1,218 @@ +no_cache(); + +$oContext = new UserContext(); +$operation = utils::ReadParam('operation', ''); +$sFilter = stripslashes(utils::ReadParam('filter', '')); +$sEncoding = utils::ReadParam('encoding', 'serialize'); +$sClass = utils::ReadParam('class', 'bizContact'); +$sStyle = utils::ReadParam('style', 'list'); + +switch($operation) +{ + case 'wizard_helper_preview': + $sJson = utils::ReadParam('json_obj', '', 'post'); + $oWizardHelper = WizardHelper::FromJSON($sJson); + $oObj = $oWizardHelper->GetTargetObject(); + $oObj->DisplayBareDetails($oPage); + break; + + case 'wizard_helper': + $sJson = utils::ReadParam('json_obj', ''); + $oWizardHelper = WizardHelper::FromJSON($sJson); + $oObj = $oWizardHelper->GetTargetObject(); + foreach($oWizardHelper->GetFieldsForDefaultValue() as $sAttCode) + { + $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); + $oWizardHelper->SetDefaultValue($sAttCode, $oAttDef->GetDefaultValue()); + } + foreach($oWizardHelper->GetFieldsForAllowedValues() as $sAttCode) + { + $oWizardHelper->SetAllowedValuesHtml($sAttCode, "Possible values ($sAttCode)"); + } + $oPage->add($oWizardHelper->ToJSON()); + break; + + case 'ajax': + if ($sFilter != "") + { + if ($sEncoding == 'sibusql') + { + $oFilter = CMDBSearchFilter::FromSibusQL($sFilter); + } + else + { + $oFilter = CMDBSearchFilter::unserialize($sFilter); + } + $oDisplayBlock = new DisplayBlock($oFilter, $sStyle, false); + $oDisplayBlock->RenderContent($oPage); + } + else + { + $oPage->p("Invalid query (empty filter)."); + } + break; + + case 'details': + $key = utils::ReadParam('id', 0); + $oFilter = $oContext->NewFilter($sClass); + $oFilter->AddCondition('pkey', $key, '='); + $oDisplayBlock = new DisplayBlock($oFilter, 'details', false); + $oDisplayBlock->RenderContent($oPage); + break; + + case 'preview': + $key = utils::ReadParam('id', 0); + $oFilter = $oContext->NewFilter($sClass); + $oFilter->AddCondition('pkey', $key, '='); + $oDisplayBlock = new DisplayBlock($oFilter, 'preview', false); + $oDisplayBlock->RenderContent($oPage); + break; + + case 'pie_chart': + $sGroupBy = utils::ReadParam('group_by', ''); + if ($sFilter != '') + { + if ($sEncoding == 'sibusql') + { + $oFilter = CMDBSearchFilter::FromSibusQL($sFilter); + } + else + { + $oFilter = CMDBSearchFilter::unserialize($sFilter); + } + $oDisplayBlock = new DisplayBlock($oFilter, 'pie_chart_ajax', false); + $oDisplayBlock->RenderContent($oPage, array('group_by' => $sGroupBy)); + } + else + { + + $oPage->add("\n3d pie\n."); + } + break; + + case 'open_flash_chart': + $aParams = utils::ReadParam('params', array()); + if ($sFilter != '') + { + if ($sEncoding == 'sibusql') + { + $oFilter = CMDBSearchFilter::FromSibusQL($sFilter); + } + else + { + $oFilter = CMDBSearchFilter::unserialize($sFilter); + } + $oDisplayBlock = new DisplayBlock($oFilter, 'open_flash_chart_ajax', false); + $oDisplayBlock->RenderContent($oPage, $aParams); + } + else + { + + $oPage->add("\n3d pie\n."); + } + break; + + case 'modal_details': + $key = utils::ReadParam('id', 0); + $oFilter = $oContext->NewFilter($sClass); + $oFilter->AddCondition('pkey', $key, '='); + $oPage->Add("

Object Details

\n"); + $oDisplayBlock = new DisplayBlock($oFilter, 'details', false); + $oDisplayBlock->RenderContent($oPage); + $oPage->Add("\n"); + break; + + case 'ui.linkswidget': + $sClass = utils::ReadParam('sclass', 'bizContact'); + $sAttCode = utils::ReadParam('attCode', 'name'); + $sOrg = utils::ReadParam('org_id', ''); + $sName = utils::ReadParam('q', ''); + $iMaxCount = utils::ReadParam('max', 30); + UILinksWidget::Autocomplete($oPage, $oContext, $sClass, $sAttCode, $sName, $iMaxCount); + break; + + case 'ui.linkswidget.linkedset': + $sClass = utils::ReadParam('sclass', 'bizContact'); + $sJSONSet = stripslashes(utils::ReadParam('sset', '')); + $sExtKeyToMe = utils::ReadParam('sextkeytome', ''); + UILinksWidget::RenderSet($oPage, $sClass, $sJSONSet, $sExtKeyToMe); + break; + + case 'autocomplete': + $key = utils::ReadParam('id', 0); + $sClass = utils::ReadParam('sclass', 'bizContact'); + $sAttCode = utils::ReadParam('attCode', 'name'); + $sOrg = utils::ReadParam('org_id', ''); + $sName = utils::ReadParam('q', ''); + $iMaxCount = utils::ReadParam('max', 30); + $aArgs = array(); + if (!empty($key)) + { + if ($oThis = MetaModel::GetObject($sClass, $key)) + { + $aArgs['*this*'] = $oThis; + } + } + $aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs, $sName); + $iCount = 0; + foreach($aAllowedValues as $key => $value) + { + $oPage->add($value."|".$key."\n"); + if ($iCount++) break; + } + break; + + case 'link': + $sClass = utils::ReadParam('sclass', 'logInfra'); + $sAttCode = utils::ReadParam('attCode', 'name'); + //$sOrg = utils::ReadParam('org_id', ''); + $sName = utils::ReadParam('q', ''); + $iMaxCount = utils::ReadParam('max', 30); + $iCount = 0; + $oFilter = $oContext->NewFilter($sClass); + $oFilter->AddCondition($sAttCode, $sName, 'Begins with'); + //$oFilter->AddCondition('org_id', $sOrg); + $oSet = new CMDBObjectSet($oFilter, array($sAttCode => true)); + while( ($iCount < $iMaxCount) && ($oObj = $oSet->fetch()) ) + { + $oPage->add($oObj->GetAsHTML($sAttCode)."|".$oObj->GetKey()."\n"); + $iCount++; + } + break; + + case 'create': + case 'create_menu': + $sClass = utils::ReadParam('class', ''); + $sFilter = utils::ReadParam('filter', ''); + menuNode::DisplayCreationForm($oPage, $sClass, $sFilter); + break; + + case 'combo_options': + $oFilter = CMDBSearchFilter::FromSibusQL($sFilter); + $oSet = new CMDBObjectSet($oFilter); + while( $oObj = $oSet->fetch()) + { + $oPage->add(''); + } + break; + + default: + $oPage->p("Invalid query."); +} +$oPage->output(); +?> diff --git a/pages/audit.php b/pages/audit.php new file mode 100644 index 000000000..6f69cfdbb --- /dev/null +++ b/pages/audit.php @@ -0,0 +1,149 @@ +GetObject('AuditRule', $iRuleId); + $sSibusql = $oRule->Get('query'); + $oRuleFilter = DBObjectSearch::FromSibusQL($sSibusql); + if ($oRule->Get('valid_flag') == 'false') + { + // The query returns directly the invalid elements + $oFilter = $oRuleFilter; + $oFilter->MergeWith($oDefinitionFilter); + $oErrorObjectSet = new CMDBObjectSet($oFilter); + } + else + { + // The query returns only the valid elements, all the others are invalid + $oFilter = $oRuleFilter; + $oErrorObjectSet = new CMDBObjectSet($oFilter); + $aValidIds = array(0); // Make sure that we have at least one value in the list + while($oObj = $oErrorObjectSet->Fetch()) + { + $aValidIds[] = $oObj->GetKey(); + } + $oFilter = $oDefinitionFilter; + $oFilter->AddCondition('pkey', $aValidIds, 'NOTIN'); + $oErrorObjectSet = new CMDBObjectSet($oFilter); + } + return $oErrorObjectSet; +} + +function GetReportColor($iTotal, $iErrors) +{ + $sResult = 'red'; + if ( ($iTotal == 0) || ($iErrors / $iTotal) <= 0.05 ) + { + $sResult = 'green'; + } + else if ( ($iErrors / $iTotal) <= 0.25 ) + { + $sResult = 'orange'; + } + return $sResult; +} + +switch($operation) +{ + case 'errors': + $iCategory = utils::ReadParam('category', ''); + $iRuleIndex = utils::ReadParam('rule', 0); + + $oContext = new UserContext(); + $oAuditCategory = $oContext->GetObject('AuditCategory', $iCategory); + $oDefinitionFilter = DBObjectSearch::FromSibusQL($oAuditCategory->Get('definition_set')); + if (!empty($currentOrganization)) + { + $oDefinitionFilter->AddCondition('org_id', $currentOrganization); + } + $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); + $oErrorObjectSet = GetRuleResultSet($iRuleIndex, $oDefinitionFilter); + $oAuditRule = $oContext->GetObject('AuditRule', $iRuleIndex); + $oP->add(''); + $oP->p('[Back to audit results]'); + cmdbAbstractObject::DisplaySet($oP, $oErrorObjectSet); + break; + + case 'audit': + default: + $oP->add(''); + $oAuditFilter = new CMDBSearchFilter('AuditCategory'); + $oCategoriesSet = new DBObjectSet($oAuditFilter); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("
\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + while($oAuditCategory = $oCategoriesSet->fetch()) + { + $oDefinitionFilter = DBObjectSearch::FromSibusQL($oAuditCategory->Get('definition_set')); + $aObjectsWithErrors = array(); + if (!empty($currentOrganization)) + { + $oDefinitionFilter->AddCondition('org_id', $currentOrganization); + } + $aResults = array(); + $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); + $iCount = $oDefinitionSet->Count(); + $oRulesFilter = new CMDBSearchFilter('AuditRule'); + $oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey()); + $oRulesSet = new DBObjectSet($oRulesFilter); + while($oAuditRule = $oRulesSet->fetch() ) + { + $aRow = array(); + $aRow['description'] = $oAuditRule->Get('name'); + if ($iCount == 0) + { + // nothing to check, really ! + $aRow['nb_errors'] = "GetKey()."&rule=".$oAuditRule->GetKey()."\">0"; + $aRow['percent_ok'] = '100.00'; + $aRow['class'] = GetReportColor($iCount, 0); + } + else + { + $oRuleFilter = DBObjectSearch::FromSibusQL($oAuditRule->Get('query')); + $oErrorObjectSet = GetRuleResultSet($oAuditRule->GetKey(), $oDefinitionFilter); + $iErrorsCount = $oErrorObjectSet->Count(); + while($oObj = $oErrorObjectSet->Fetch()) + { + $aObjectsWithErrors[$oObj->GetKey()] = true; + } + $aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount"; + $aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount)); + $aRow['class'] = GetReportColor($iCount, $iErrorsCount); + } + $aResults[] = $aRow; + $iTotalErrors = count($aObjectsWithErrors); + $sOverallPercentOk = ($iCount == 0) ? '100.00' : sprintf('%.2f', 100.0 * (($iCount - $iTotalErrors) / $iCount)); + $sClass = GetReportColor($iCount, $iTotalErrors); + + } + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + foreach($aResults as $aRow) + { + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + } + } + $oP->add("
Audit Rule# Objects# Errors% Ok
".$oAuditCategory->GetName()."$iCount$iTotalErrors$sOverallPercentOk %
 ".$aRow['description']."".$aRow['nb_errors']."".$aRow['percent_ok']." %
\n"); + $oP->add("
\n"); +} + +$oP->output(); +?> diff --git a/pages/csvimport.php b/pages/csvimport.php new file mode 100644 index 000000000..64f720726 --- /dev/null +++ b/pages/csvimport.php @@ -0,0 +1,846 @@ + '); + +class CSVParser +{ + private $m_sCSVData; + private $m_sSep; + private $m_iSkip; + + public function __construct($sTxt) + { + $this->m_sCSVData = $sTxt; + } + + public function SetSeparator($sSep) + { + $this->m_sSep = $sSep; + } + public function GetSeparator() + { + return $this->m_sSep; + } + + public function SetSkipLines($iSkip) + { + $this->m_iSkip = $iSkip; + } + public function GetSkipLines() + { + return $this->m_iSkip; + } + + public function GuessSeparator() + { + // Note: skip the first line anyway + + $aKnownSeps = array(';', ',', "\t"); // Use double quote for special chars!!! + $aStatsBySeparator = array(); + foreach ($aKnownSeps as $sSep) + { + $aStatsBySeparator[$sSep] = array(); + } + + foreach(split("\n", $this->m_sCSVData) as $sLine) + { + $sLine = trim($sLine); + if (substr($sLine, 0, 1) == '#') continue; + if (empty($sLine)) continue; + + $aLineCharsCount = count_chars($sLine, 0); + foreach ($aKnownSeps as $sSep) + { + $aStatsBySeparator[$sSep][] = $aLineCharsCount[ord($sSep)]; + } + } + + // Default to ',' + $this->SetSeparator(","); + + foreach ($aKnownSeps as $sSep) + { + // Note: this function is NOT available :-( + // stats_variance($aStatsBySeparator[$sSep]); + $iMin = min($aStatsBySeparator[$sSep]); + $iMax = max($aStatsBySeparator[$sSep]); + if (($iMin == $iMax) && ($iMax > 0)) + { + $this->SetSeparator($sSep); + break; + } + } + return $this->GetSeparator(); + } + + public function GuessSkipLines() + { + // Take the FIRST -valuable- LINE ONLY + // If there is a number, then for sure this is not a header line + // Otherwise, we may consider that there is one line to skip + foreach(split("\n", $this->m_sCSVData) as $sLine) + { + $sLine = trim($sLine); + if (substr($sLine, 0, 1) == '#') continue; + if (empty($sLine)) continue; + + foreach (split($this->m_sSep, $sLine) as $value) + { + if (is_numeric($value)) + { + $this->SetSkipLines(0); + return 0; + } + } + $this->SetSkipLines(1); + return 1; + } + } + + function ToArray($aFieldMap, $iMax = 0) + { + // $aFieldMap is an array of col_index=>col_name + // $iMax is a limit + $aRes = array(); + + $iCount = 0; + $iSkipped = 0; + foreach(split("\n", $this->m_sCSVData) as $sLine) + { + $sLine = trim($sLine); + if (substr($sLine, 0, 1) == '#') continue; + if (empty($sLine)) continue; + + if ($iSkipped < $this->m_iSkip) + { + $iSkipped++; + continue; + } + + foreach (split($this->m_sSep, $sLine) as $iCol=>$sValue) + { + if (is_array($aFieldMap)) $sColRef = $aFieldMap[$iCol]; + else $sColRef = "field$iCol"; + $aRes[$iCount][$sColRef] = $sValue; + } + + $iCount++; + if (($iMax > 0) && ($iCount >= $iMax)) break; + } + return $aRes; + } + + public function ListFields() + { + // Take the first valuable line + foreach(split("\n", $this->m_sCSVData) as $sLine) + { + $sLine = trim($sLine); + if (substr($sLine, 0, 1) == '#') continue; + if (empty($sLine)) continue; + // We've got the first valuable line, that's it! + break; + } + + $aRet = array(); + foreach (split($this->m_sSep, $sLine) as $iCol=>$value) + { + if ($this->m_iSkip == 0) + { + // No header to help us + $sLabel = "field $iCol"; + } + else + { + $sLabel = "$value"; + } + $aRet[] = $sLabel; + } + return $aRet; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// External key/field naming conventions (sharing the naming space with std attributes +/////////////////////////////////////////////////////////////////////////////// + +function IsExtKeyField($sColDesc) +{ + return ($iPos = strpos($sColDesc, EXTKEY_SEP)); +} + +function GetExtKeyFieldCodes($sColDesc) +{ + $iPos = strpos($sColDesc, EXTKEY_SEP); + return array( + substr($sColDesc, 0, $iPos), + substr($sColDesc, $iPos + strlen(EXTKEY_SEP)) + ); +} + +function MakeExtFieldLabel($sClass, $sExtKeyAttCode, $sForeignAttCode) +{ + $oExtKeyAtt = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode); + $oForeignAtt = MetaModel::GetAttributeDef($oExtKeyAtt->GetTargetClass(), $sForeignAttCode); + + return $oExtKeyAtt->GetLabel().EXTKEY_LABELSEP.$oForeignAtt->GetLabel(); +} + +function MakeExtFieldSelectValue($sAttCode, $sExtAttCode) +{ + return $sAttCode.EXTKEY_SEP.$sExtAttCode; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +function ShowTableForm($oPage, $oCSVParser, $sClass) +{ + $aData = $oCSVParser->ToArray(null, 3); + $aColToRow = array(); + foreach($aData as $aRow) + { + foreach ($aRow as $sFieldId=>$sValue) + { + $aColToRow[$sFieldId][] = $sValue; + } + } + + $aFields = array(); + foreach($oCSVParser->ListFields() as $iFieldIndex=>$sFieldName) + { + $sSelField = ""; + + $sCHECKED = ($sFieldName == "pkey" || MetaModel::IsReconcKey($sClass, $sFoundAttCode)) ? " CHECKED" : ""; + $sSelField .= " "; + + $aFields["field$iFieldIndex"]["label"] = $sSelField; + $aFields["field$iFieldIndex"]["value"] = $aColToRow["field$iFieldIndex"]; + } + $oPage->details($aFields); +} + +function PrepareObject(&$oTargetObj, $aRowData, $aAttList, $aExtKeys, &$aWarnings, &$aErrors) +{ + $aResults = array(); + $aWarnings = array(); + $aErrors = array(); + + // External keys reconciliation + // + foreach($aExtKeys as $sAttCode=>$aKeyConfig) + { + $oExtKey = MetaModel::GetAttributeDef(get_class($oTargetObj), $sAttCode); + $oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass()); + foreach ($aKeyConfig as $iCol => $sForeignAttCode) + { + // The foreign attribute is one of our reconciliation key + $sFieldId = MakeExtFieldSelectValue($sAttCode, $sForeignAttCode); + $oReconFilter->AddCondition($sForeignAttCode, $aRowData[$sFieldId], '='); + $aResults["col$iCol"]= "
".$aRowData[$sFieldId]."
"; + } + $oExtObjects = new CMDBObjectSet($oReconFilter); + switch($oExtObjects->Count()) + { + case 0: + $aErrors[$sAttCode] = "Object not found"; + $aResults[$sAttCode]= "
".$aErrors[$sAttCode]."
"; + break; + case 1: + // Do change the external key attribute + $oForeignObj = $oExtObjects->Fetch(); + $oTargetObj->Set($sAttCode, $oForeignObj->GetKey()); + + // Report it + if (array_key_exists($sAttCode, $oTargetObj->ListChanges())) + { + $aResults[$sAttCode]= "
".$oForeignObj->GetHyperLink()."
"; + } + else + { + $aResults[$sAttCode]= "
".$oForeignObj->GetHyperLink()."
"; + } + break; + default: + $aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches"; + $aResults[$sAttCode]= "
".$aErrors[$sAttCode]."
"; + } + } + + // Set the object attributes + // + foreach ($aAttList as $iCol => $sAttCode) + { + $oTargetObj->Set($sAttCode, $aRowData[$sAttCode]); + } + + // Reporting on fields + // + $aChangedFields = $oTargetObj->ListChanges(); + foreach ($aAttList as $iCol => $sAttCode) + { + // By default... nothing happens + $sClass = ""; + $sMoreInfo = ""; + + // Override if the attribute has changed + if (array_key_exists($sAttCode, $aChangedFields)) + { + $sClass = "csvimport_ok"; + } + + // Override if a warning is found + if (isset($aWarnings[$sAttCode])) + { + $sClass = "csvimport_warning"; + $sMoreInfo .= ", ".$aWarnings[$sAttCode]; + } + + // Override if an error is found + if (isset($aErrors[$sAttCode])) + { + $sClass = "csvimport_error"; + $sMoreInfo = ", ".$aErrors[$sAttCode]; + } + + $aResults["col$iCol"]= "
".$aRowData[$sAttCode].$sMoreInfo."
"; + } + + // Checks + // + if (!$oTargetObj->CheckConsistency()) + { + $aErrors["GLOBAL"] = "Attributes not consistent with each others"; + } + return $aResults; +} + + +function CreateObject(&$aResult, $iRow, $sClass, $aRowData, $aAttList, $aExtKeys, CMDBChange $oChange = null) +{ + $oTargetObj = MetaModel::NewObject($sClass); + $aResult[$iRow] = PrepareObject($oTargetObj, $aRowData, $aAttList, $aExtKeys, $aWarnings, $aErrors); + + if (count($aErrors) > 0) + { + $sErrors = implode(', ', $aErrors); + $aResult[$iRow]["__STATUS__"] = "Unexpected attribute value(s)"; + return; + } + + // Check that any external key will have a value proposed + // Could be said once for all rows !!! + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAtt) + { + if (!$oAtt->IsExternalKey()) continue; + //if (!in_array($sAttCode, $aAttList)) + //{ + // $aResult[$iRow]["__STATUS__"] = "Could not be created - Missing external key (".$oAtt->GetLabel().")"; + // return; + //} + } + + // Optionaly record the results + // + if ($oChange) + { + $newID = $oTargetObj->DBInsertTracked($oChange); + $aResult[$iRow]["__STATUS__"] = "Created: ".$oTargetObj->GetHyperLink($newID); + } + else + { + $aResult[$iRow]["__STATUS__"] = "Create"; + } + +} + +function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, $aAttList, $aExtKeys, CMDBChange $oChange = null) +{ + $aResult[$iRow] = PrepareObject($oTargetObj, $aRowData, $aAttList, $aExtKeys, $aWarnings, $aErrors); + + // Reporting + // + if (count($aErrors) > 0) + { + $sErrors = implode(', ', $aErrors); + $aResult[$iRow]["__STATUS__"] = "Unexpected attribute value(s)"; + return; + } + + $aChangedFields = $oTargetObj->ListChanges(); + if (count($aChangedFields) > 0) + { + $sVerb = $oChange ? "Updated" : "Update"; + $aResult[$iRow]["__STATUS__"] = "$sVerb ".count($aChangedFields)." cols"; + + // Optionaly record the results + // + if ($oChange) + { + $oTargetObj->DBUpdateTracked($oChange); + } + } + else + { + $aResult[$iRow]["__STATUS__"] = "No change"; + } +} + +function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CMDBChange $oChange = null) +{ + // Note: $oChange can be null, in which case the aim is to check what would be done + + // Setup field mapping: sort out between values and other specific columns + // + $iPKeyId = null; + $aReconcilKeys = array(); + $aAttList = array(); + $aExtKeys = array(); + foreach($aFieldMap as $sFieldId=>$sColDesc) + { + $iFieldId = (int) substr($sFieldId, strlen("field")); + if ($sColDesc == "pkey") + { + // Skip ! + $iPKeyId = $iFieldId; + } + elseif ($sColDesc == "__none__") + { + // Skip ! + } + elseif (IsExtKeyField($sColDesc)) + { + list($sExtKeyAttCode, $sExtReconcKeyAttCode) = GetExtKeyFieldCodes($sColDesc); + $aExtKeys[$sExtKeyAttCode][$iFieldId] = $sExtReconcKeyAttCode; + } + elseif (array_key_exists($sFieldId, $aIsReconcKey)) + { + $aReconcilKeys[$iFieldId] = $sColDesc; + $aAttList[$iFieldId] = $sColDesc; // A reconciliation key is also a field + } + else + { + // $sColDesc is an attribute code + // + $aAttList[$iFieldId] = $sColDesc; + } + } + + // Setup result presentation + // + $aDisplayConfig = array(); + $aDisplayConfig["__RECONCILIATION__"] = array("label"=>"Reconciliation", "description"=>""); + $aDisplayConfig["__STATUS__"] = array("label"=>"Status", "description"=>""); + if (isset($iPKeyId)) + { + $aDisplayConfig["col$iPKeyId"] = array("label"=>"pkey", "description"=>""); + } + foreach($aReconcilKeys as $iCol=>$sAttCode) + { + $sLabel = MetaModel::GetAttributeDef($sClass, $sAttCode)->GetLabel(); + $aDisplayConfig["col$iCol"] = array("label"=>"$sLabel", "description"=>""); + } + foreach($aExtKeys as $sAttCode=>$aKeyConfig) + { + $oExtKeyAtt = MetaModel::GetAttributeDef($sClass, $sAttCode); + $sLabel = $oExtKeyAtt->GetLabel(); + $aDisplayConfig[$sAttCode] = array("label"=>"$sLabel", "description"=>""); + foreach ($aKeyConfig as $iCol => $sForeignAttCode) + { + // The foreign attribute is one of our reconciliation key + + $sLabel = MakeExtFieldLabel($sClass, $sAttCode, $sForeignAttCode); + $aDisplayConfig["col$iCol"] = array("label"=>"$sLabel", "description"=>""); + } + } + foreach ($aAttList as $iCol => $sAttCode) + { + $sLabel = MetaModel::GetAttributeDef($sClass, $sAttCode)->GetLabel(); + $aDisplayConfig["col$iCol"] = array("label"=>"$sLabel", "description"=>""); + } + + // Compute the results + // + $aResult = array(); + foreach($oCSVParser->ToArray(array_values($aFieldMap)) as $iRow => $aRowData) + { + $oReconciliationFilter = new CMDBSearchFilter($sClass); + if (isset($iPKeyId)) + { + $oReconciliationFilter->AddCondition("pkey", $aRowData["pkey"], '='); + } + foreach($aReconcilKeys as $iCol=>$sAttCode) + { + $sSearchAttCode = $aFieldMap['field'.$iCol]; + $oReconciliationFilter->AddCondition($sSearchAttCode, $aRowData[$sSearchAttCode], '='); + } + $oReconciliationSet = new CMDBObjectSet($oReconciliationFilter); + switch($oReconciliationSet->Count()) + { + case 0: + CreateObject($aResult, $iRow, $sClass, $aRowData, $aAttList, $aExtKeys, $oChange); + // $aResult[$iRow]["__STATUS__"]=> set in CreateObject + $aResult[$iRow]["__RECONCILIATION__"] = "Object not found"; + break; + case 1: + $oTargetObj = $oReconciliationSet->Fetch(); + UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $aAttList, $aExtKeys, $oChange); + $aResult[$iRow]["__RECONCILIATION__"] = "Found a ".$oTargetObj->GetHyperLink("match"); + // $aResult[$iRow]["__STATUS__"]=> set in UpdateObject + break; + default: + foreach ($aAttList as $iCol => $sAttCode) + { + $aResult[$iRow]["col$iCol"]= $aRowData[$sAttCode]; + } + $aResult[$iRow]["__RECONCILIATION__"] = "Found ".$oReconciliationSet->Count()." matches"; + $aResult[$iRow]["__STATUS__"]= "skipped"; + } + + // Whatever happened, do report the reconciliation values + if (isset($iPKeyId)) + { + $aResult[$iRow]["col$iPKeyId"] = "
".$aRowData["pkey"]."
"; + } + foreach($aReconcilKeys as $iCol=>$sAttCode) + { + $aResult[$iRow]["col$iCol"] = "
".$aRowData[$sAttCode]."
"; + } + } + $oPage->table($aDisplayConfig, $aResult); +} + +/////////////////////////////////////////////////////////////////////////////// +// Wizard entry points +/////////////////////////////////////////////////////////////////////////////// + +function Do_Welcome($oPage, $sClass) +{ + $sWiztep = "1_welcome"; + $oPage->p("

Bulk load from CSV data / step 1

"); + + $sCSVData = utils::ReadPostedParam('csvdata'); + + $oPage->add("
"); + $oPage->MakeClassesSelect("class", $sClass, 50); + //$oPage->Add(""); + $oPage->add("
"); + $oPage->add(""); + $oPage->add("
"); + $oPage->add(""); + $oPage->add("
\n"); + $oPage->add("
"); + + // As a help to the end-user, let's display the list of possible fields + // for a class, that can be copied/pasted into the CSV area. + $sCurrentList = ""; + $aHeadersList = array(); + foreach(MetaModel::GetClasses('bizmodel') as $sClassName) + { + $aList = MetaModel::GetZListItems($sClassName, 'details'); + $aHeader = array(); + // $aHeader[] = MetaModel::GetKeyLabel($sClassName); + $aHeader[] = 'pkey'; // Should be what's coded on the line above... but there is a bug + foreach($aList as $sAttCode) + { + $aHeader[] = MetaModel::GetLabel($sClassName, $sAttCode); + } + + $sAttributes = implode(",", $aHeader); + $aHeadersList[$sClassName] = $sAttributes; + + if($sClassName == $sClass) + { + // this class is currently selected + $sCurrentList = $sAttributes; + } + } + // Store all the values in a variable client-side + $aScript = array(); + foreach($aHeadersList as $sClassName => $sAttributes) + { + $aScript[] = "'$sClassName':'$sAttributes'"; + } + $oPage->add("\n"); + + $oPage->add_ready_script("$('#select_class').change( function() {DisplayFields(this.value);} );"); + + $oPage->add("Fields for this object: "); + +} + +function Do_Format($oPage, $sClass) +{ + $oPage->p("

Bulk load from CSV data / step 2

"); + $sWiztep = "2_format"; + + $sCSVData = utils::ReadPostedParam('csvdata'); + $oCSVParser = new CSVParser($sCSVData); + $sSep = $oCSVParser->GuessSeparator(); + $iSkip = $oCSVParser->GuessSkipLines(); + + // No data ? + $aData = $oCSVParser->ToArray(null); + $iTarget = count($aData); + if ($iTarget == 0) + { + $oPage->add("Empty data set..."); + $oPage->add("
"); + $oPage->add(""); + $oPage->add(""); + $oPage->add(""); + $oPage->add("
"); + } + + // Guess the format : + $oPage->p("Guessed separator: '$sSep' (ASCII=".ord($sSep).")"); + $oPage->p("Guessed # of lines to skip: $iSkip"); + + $oPage->p("Target: $iTarget rows"); + + $oPage->Add("
"); + ShowTableForm($oPage, $oCSVParser, $sClass); + $oPage->Add(""); + $oPage->Add(""); + $oPage->Add(""); + $oPage->Add(""); + + $oPage->Add(""); + $oPage->add(""); + $oPage->Add(""); + $oPage->Add("
"); +} + +function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null) +{ + $sCSVData = utils::ReadPostedParam('csvdata'); + $sSep = utils::ReadPostedParam('separator'); + $iSkip = utils::ReadPostedParam('skiplines'); + $aFieldMap = utils::ReadPostedParam('fmap'); + $aIsReconcKey = utils::ReadPostedParam('iskey'); + + $oCSVParser = new CSVParser($sCSVData); + $oCSVParser->SetSeparator($sSep); + $oCSVParser->SetSkipLines($iSkip); + $aData = $oCSVParser->ToArray(null); + $iTarget = count($aData); + + $oPage->p("

Goal summary

"); + $oPage->p("Target: $iTarget rows"); + + $aSampleData = $oCSVParser->ToArray(null, 5); + $aDisplayConfig = array(); + foreach ($aFieldMap as $sFieldId=>$sColDesc) + { + if (array_key_exists($sFieldId, $aIsReconcKey)) + { + $sReconcKey = " [search]"; + } + else + { + $sReconcKey = ""; + } + + if ($sColDesc == "pkey") + { + $aDisplayConfig[$sFieldId] = array("label"=>"Private key $sReconcKey", "description"=>"blah pkey"); + } + elseif ($sColDesc == "__none__") + { + // Skip ! + } + else if (MetaModel::IsValidAttCode($sClass, $sColDesc)) + { + $sAttCode = $sColDesc; + $sLabel = MetaModel::GetAttributeDef($sClass, $sAttCode)->GetLabel(); + $aDisplayConfig[$sFieldId] = array("label"=>"$sLabel$sReconcKey", "description"=>""); + } + elseif (IsExtKeyField($sColDesc)) + { + list($sExtKeyAttCode, $sForeignAttCode) = GetExtKeyFieldCodes($sColDesc); + $aDisplayConfig[$sFieldId] = array("label"=>MakeExtFieldLabel($sClass, $sExtKeyAttCode, $sForeignAttCode), "description"=>""); + } + else + { + // ??? + $aDisplayConfig[$sFieldId] = array("label"=>"-?-?-$sColDesc-?-?-", "description"=>""); + } + } + $oPage->table($aDisplayConfig, $aSampleData); + + if ($oChange) + { + $oPage->p("

Processing...

"); + } + else + { + $oPage->p("

Check...

"); + } + ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, $oChange); + + $oPage->add("
"); + $oPage->add(""); + $oPage->add(""); + $oPage->add(""); + $oPage->add(""); + $oPage->add_input_hidden("fmap", $aFieldMap); + $oPage->add_input_hidden("iskey", $aIsReconcKey); +} + +function Do_Verify($oPage, $sClass) +{ + $oPage->p("

Bulk load from CSV data / step 3

"); + $sWiztep = "3_verify"; + + DoProcessOrVerify($oPage, $sClass, null); + // FORM started by DoProcessOrVerify... + + $oPage->add(""); + $oPage->add(""); + $oPage->add(""); + $oPage->add("
"); +} + +function Do_Execute($oPage, $sClass) +{ + $oPage->p("

Bulk load from CSV data / step 4

"); + $sWiztep = "4_execute"; + + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "CSV Import"); + $iChangeId = $oMyChange->DBInsert(); + + DoProcessOrVerify($oPage, $sClass, $oMyChange); + + // FORM started by DoProcessOrVerify... + $oPage->add(""); + $oPage->add(""); + $oPage->add(""); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// M a i n P r o g r a m +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +$sFromWiztep = utils::ReadPostedParam('fromwiztep', ''); +$sClass = utils::ReadPostedParam('class', ''); +$sTodo = utils::ReadPostedParam('todo', ''); + +switch($sFromWiztep) +{ + case '': + Do_Welcome($oPage, $sClass); + break; + + case '1_welcome': + if ($sTodo == "Next") Do_Format($oPage, $sClass); + else trigger_error("Wrong argument todo='$sTodo'", E_USER_ERROR); + break; + + case '2_format': + if ($sTodo == "Next") Do_Verify($oPage, $sClass); + else Do_Welcome($oPage, $sClass); + break; + + case '3_verify': + if ($sTodo == "Next") Do_Execute($oPage, $sClass); + else Do_Format($oPage, $sClass); + break; + + case '4_execute': + if ($sTodo == "Next") trigger_error("Wrong argument todo='$sTodo'", E_USER_ERROR); + else Do_Verify($oPage, $sClass); + break; + + default: + trigger_error("Wrong argument fromwiztep='$sFromWiztep'", E_USER_ERROR); +} + +$oPage->output(); +?> diff --git a/pages/data_generator.php b/pages/data_generator.php new file mode 100644 index 000000000..351269d18 --- /dev/null +++ b/pages/data_generator.php @@ -0,0 +1,321 @@ +\n"; + echo "DEBUG: \$_SERVER\n"; + print_r($_SERVER); + echo "\n"; + exit; +} +if (!UserRights::Login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) +{ + header('WWW-Authenticate: Basic realm="iTop"'); + header('HTTP/1.0 401 Unauthorized'); + echo 'Authentication failed !'; + exit; +} + +$oPage = new iTopWebPage("iTop Data Generator", $currentOrganization); +$oPage->no_cache(); + +// From now on the context is limited to the the selected organization ?? + +// Retrieve the root node for the menu +$oSearchFilter = $oContext->NewFilter("menuNode"); +$oSearchFilter->AddCondition('parent_id', 0, '='); +// There may be more criteria added later to have a specific menu based on the user's profile +$oSet = new CMDBObjectSet($oSearchFilter, array('rank' => true)); +while ($oRootMenuNode = $oSet->Fetch()) +{ + $oRootMenuNode->DisplayMenu($oPage, $oContext, $iActiveNodeId, null, $oAppContext->GetAsHash()); +} +/** + * The (ordered) list of classes for which to generate objects + * + * Each class in this list must implement a non-static Generate(cmdbDataGenerator $oGenerator) method + */ +//$aClassesToGenerate = array('bizOrganization' /* This one is special and must go first */, 'bizService', 'bizContact', 'bizPC', 'bizNetworkDevice'); +$aClassesToGenerate = array('bizOrganization' /* This one is special and must go first */, 'bizLocation', 'bizPC', 'bizNetworkDevice', 'bizPerson', 'bizIncidentTicket', 'bizInfraGroup', 'bizInfraInfra'); + +///////////////////////////////////////////////////////////////////////////////////// +// Actual actions of the page +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Populate an organization with objects of each class listed in the (global) $aClassesToGenerate array + * + * @param web_page $oPage The object used for the HTML output + * @param cmdbGenerator $oGenerator The object used for the generation of the objects + * @param string $sSize An enum specifying (roughly) how many objects of each class to create: one of 'small', 'medium', 'big', 'huge' or 'max' + */ +function PopulateOrganization(CMDBChange $oMyChange, web_page $oPage, cmdbDataGenerator $oGenerator, $sSize = 'small') +{ + global $aClassesToGenerate; + + for ($i=1 /* skip the first one (i=0) which is the org itself */; $iGenerate($oGenerator); + // By rom + // $oObject->DBInsert(); + $oObject->DBInsertTracked($oMyChange); + + //$oObject->DisplayDetails($oPage); + } + } + $oPage->p("$nbObjects $sClass objects created."); + } +} + +/** + * Delete an organization and all the instances of 'Object' belonging to this organization + * + * @param web_page $oPage The object used for the HTML output + * @param string $sOrganizationCode The code (pkey) of the organization to delete + */ +function DeleteOrganization($oMyChange, $oPage, $sOrganizationCode) +{ + $oOrg = MetaModel::GetObject('bizOrganization', $sOrganizationCode); + if ($oOrg == null) + { + $oPage->p("Organization '$sOrganizationCode' already deleted!!"); + } + else + { + // Delete all the objects linked to this organization + $oFilter = new CMDBSearchFilter('logRealObject'); + $oFilter->AddCondition('organization', $sOrganizationCode, '='); + $oSet = new CMDBObjectSet($oFilter); + $countDeleted = $oSet->Count(); + MetaModel::BulkDeleteTracked($oMyChange, $oFilter); // Should do a one by one delete to let the objects do their own cleanup ! + $oPage->p("$countDeleted object(s) deleted!!"); + + $oOrg->DBDeleteTracked($oMyChange); + $oPage->p("Ok, organization '$sOrganizationCode' deleted!"); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// M a i n P r o g r a m +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +$operation = utils::ReadParam('operation', ''); + +$oPage->add("
\n"); +$oPage->add("
\n"); + +switch($operation) +{ + + case 'specify_generate': + // Display a form to specify what to generate + $oPage->p("iTop Data Generator\n"); + $oPage->add("
\n"); + $oPage->add("Number of organizations to generate: \n"); + $oPage->add(" (max ".count($aCompanies).") \n"); + $oPage->add("Size of the organizations\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("
\n"); + break; + + case 'generate': + // perform the actual generation + $iOrgCount = utils::ReadParam('org_count', 0); + $sOrgSize = utils::ReadParam('org_size', 'small'); + // By rom + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by data generator ($iOrgCount orgs of size '$sOrgSize')"); + $oMyChange->DBInsert(); + while($iOrgCount > 0) + { + set_time_limit(5*60); // let it run for 5 minutes for each organization + $oGenerator = new cmdbDataGenerator(); + // Create the new organization + $oOrg = MetaModel::NewObject('bizOrganization'); + $oOrg->Generate($oGenerator); + + // By rom + // $oOrg->DBInsert(); + $oOrg->DBInsertTracked($oMyChange); + $oGenerator->SetOrganizationId($oOrg->GetKey()); + + $oPage->p("Organization '".$oOrg->GetKey()."' created\n"); + $oOrg->DisplayDetails($oPage); + $oPage->add("
\n"); + PopulateOrganization($oMyChange, $oPage, $oGenerator, $sOrgSize); + $oPage->add("
\n"); + unset($oGenerator); + $iOrgCount--; + } + break; + + case 'specify_update': + // Specify which organization to update + $oPage->add("
\n"); + $oPage->add("Select the organization to update: \n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->p(""); + $oPage->add("Quantity of of objects to add in each class: \n"); + $oPage->add("\n"); + $oPage->p(""); + $oPage->add("  \n"); + $oPage->add("\n"); + $oPage->add("
\n"); + break; + + case 'update': + // perform the actual update + set_time_limit(5*60); // let it run for 5 minutes + $sOrganizationCode = utils::ReadParam('org', ''); + $sOrgSize = utils::ReadParam('org_size', 'small'); + if ($sOrganizationCode == '') + { + $oPage->p("Error: please specify an organization (org)."); + } + else + { + // By rom + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by data generator (update org '$sOrganizationCode', size '$sOrgSize')"); + $oMyChange->DBInsert(); + + $oPage->p("Organization '$sOrganizationCode' updated."); + $oGenerator = new cmdbDataGenerator($sOrganizationCode); + PopulateOrganization($oMyChange, $oPage, $oGenerator, $sOrgSize); + } + break; + + case 'specify_delete': + // Select an organization to be deleted + $oPage->add("
\n"); + $oPage->add("Select the organization to delete: \n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->p(""); + $oPage->add("  \n"); + $oPage->add("\n"); + $oPage->add("
\n"); + break; + + case 'confirm_delete': + // confirm the dangerous action + $sOrganizationCode = ReadParam('org', ''); + $oPage->p("iTop Data Generator\n"); + $oPage->p("Warning: you are about to delete the organization '$sOrganizationCode' and all its related objects\n"); + $oPage->add("
\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("  \n"); + $oPage->add("\n"); + $oPage->add("
\n"); + break; + + case 'delete': + // perform the actual deletion + $sOrganizationCode = ReadParam('org', ''); + if ($sOrganizationCode == '') + { + $oPage->p("Error: please specify an organization (org)."); + } + else + { + // By rom + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by data generator (delete org '$sOrganizationCode'"); + $oMyChange->DBInsert(); + + $oPage->p("Deleting '$sOrganizationCode'\n"); + DeleteOrganization($oMyChange, $oPage, $sOrganizationCode); + } + break; + + // display the menu of actions + case 'menu': + default: + $oPage->p("Data Generator Menu"); + $oPage->p("Generate one or more organizations"); + $oPage->p("Add more objects into an organization"); + $oPage->p("Delete an organization"); +} +$oPage->add("
\n"); +$oPage->add("
\n"); + +$oPage->p("Return to the data generator menu"); + +$oPage->output(); +?> diff --git a/pages/db_importer.php b/pages/db_importer.php new file mode 100644 index 000000000..7d7df9894 --- /dev/null +++ b/pages/db_importer.php @@ -0,0 +1,171 @@ +add('
'); + $oP->add('

Creation of an archive for the business model: '.$sBizModel.'

'); + $oP->p('Title of the archive: '); + $oP->p('Description of this archive: '); + $oP->p('Select the packages you want to include into this archive (When restoring the archive you will prompted to pick a package):'); + $oP->p(' The full database (schema + data).'); + $oP->p(' Only the schema but of the complete database.'); + $oP->p(' The complete business model (all the tables used by the business model, schema + data).'); + $oP->p(' Only the schema of the business model.'); + $oP->add(''); + $oP->add(''); + $oP->add(''); + $oP->add($oAppContext->GetForForm()); + $oP->add('
'); + $oP->p('Back to menu'); + break; + + case 'do_create': + $sTitle = utils::ReadParam('title', 'Unknown archive'); + $sDescription = utils::ReadParam('description', 'No description provided for this archive.'); + $bfullDump = utils::ReadParam('full', false); + $bfullSchemaDump = utils::ReadParam('full_schema', false); + $bBizDump = utils::ReadParam('biz', false); + $bBizSchemaDump = utils::ReadParam('biz_schema', false); + $sArchiveFile = '../tmp/archive1.zip'; + + $oArchive = new iTopArchive($sArchiveFile, iTopArchive::create); + $oArchive->SetTitle($sTitle); + $oArchive->SetDescription($sDescription); + if ($bfullDump) + { + $oArchive->AddDatabaseDump("Full Database Dump", "Choose this option to completely reload your database. All current data will be deleted and replaced by the backup", "full-db.sql", 'itop', array(), false); + } + + if ($bfullSchemaDump) + { + $oArchive->AddDatabaseDump("Full Schema Dump", "Choose this option to completely wipe out your database and start from an empty database", "full-schema.sql", 'itop', array(), true); + } + + if ($bBizDump || $bBizSchemaDump) + { + // compute the list of the tables involved in the business model + $aBizTables = array(); + foreach(MetaModel::GetClasses('bizmodel') as $sClass) + { + $sTable = MetaModel::DBGetTable($sClass); + $aBizTables[$sTable] = $sTable; + } + unset($aBizTables['']); + if ($bfullDump) + { + $oArchive->AddDatabaseDump("Full Business Model Dump", "Choose this option to completely reload the business model part of your database. All current business data will be deleted and replaced by the backup. Application data (like menus...) are preserved.", "biz-db.sql", 'itop', $aBizTables, false); + } + + if ($bfullSchemaDump) + { + $oArchive->AddDatabaseDump("Full Business Model Schema Dump", "Choose this option to wipe out the business data and start from an empty database. All current business data will be deleted. Application data (like menus...) are preserved.", "biz-schema.sql", 'itop', $aBizTables, true); + } + } + $oArchive->WriteCatalog(); + $oP->p("The archive '$sTitle' has been created in $sArchiveFile."); + $oP->p('Back to menu'); + break; + + case 'select_archive': + $sArchivesDir = '../tmp'; + $oP->add('
'); + $oP->add('

Importation of an archive

'); + $oP->p('Select the archive you want to import:'); + $aArchives = array(); + if ($handle = opendir($sArchivesDir)) + { + while (false !== ($sFileName = readdir($handle))) + { + if (strtolower(substr($sFileName, -3, 3)) == 'zip') + { + $oArchive = new iTopArchive('../tmp/'.$sFileName, iTopArchive::read); + if ($oArchive->IsValid()) + { + $oArchive->ReadCatalog(); + $aArchives['../tmp/'.$sFileName] = $oArchive->GetTitle(); + } + } + } + closedir($handle); + } + foreach($aArchives as $sFileName => $sTitle) + { + $oP->p(''.$sTitle); + } + $oP->add(''); + $oP->add(''); + $oP->add(''); + $oP->add($oAppContext->GetForForm()); + $oP->add('
'); + $oP->p("(Archives are searched into the directory: $sArchivesDir.)"); + $oP->p('Cancel'); + break; + + case 'select_package': + $sArchiveFile = utils::ReadParam('archive_file', ''); + $oArchive = new iTopArchive($sArchiveFile, iTopArchive::read); + $oArchive->ReadCatalog(); + $oP->add('
'); + $oP->add('

Selection of a package inside '.$oArchive->GetTitle().'

'); + $oP->p('Select the package you want to apply:'); + $aPackages = $oArchive->GetPackages(); + foreach($aPackages as $sPackageName => $aPackage) + { + $oP->p(''.$aPackage['title']); + $oP->p($aPackage['description']); + } + $oP->add(''); + $oP->add(''); + $oP->add(''); + $oP->add(''); + $oP->add($oAppContext->GetForForm()); + $oP->add('
'); + $oP->p('Cancel'); + break; + + case 'import_package': + $sArchiveFile = utils::ReadParam('archive_file', ''); + $sPackageName = utils::ReadParam('package_name', ''); + $oArchive = new iTopArchive($sArchiveFile, iTopArchive::read); + $oArchive->ReadCatalog(); + $oP->add('

Applying the package '.$sPackageName.'

'); + if($oArchive->ImportSQL($sPackageName)) + { + $oP->p('Done.'); + } + else + { + $oP->p('Sorry, an error occured while applying the package...'); + } + $oP->p('Apply another package from the same archive'); + $oP->p('Select another archive'); + $oP->p('Back to the menu'); + break; + + case 'menu': + default: + $oP->add('

Database backup & restore

'); + $oP->add('

Select one of the actions below:

'); + $oP->add('

Export the database to an archive

'); + $oP->add('

Reload the database from an archive

'); +} + +$oP->output(); +?> diff --git a/pages/export.php b/pages/export.php new file mode 100644 index 000000000..cf9f5a9e8 --- /dev/null +++ b/pages/export.php @@ -0,0 +1,64 @@ +add("Unsupported format '$sFormat'. Possible values are: html, csv or xml."); + } + } +} +if (!$oP) +{ + // Display a short message about how to use this page + $oP = new web_page("iTop - Export"); + $oP->p("General purpose export page."); + $oP->p("Parameters:"); + $oP->p("
  • expression: a SibusQL expression
  • +
  • format: (optional, default is html) the desired output format. Can be one of 'html', 'csv' or 'xml'
  • +
"); +} + +$oP->output(); +?> diff --git a/pages/graphviz.php b/pages/graphviz.php new file mode 100644 index 000000000..7530c9bff --- /dev/null +++ b/pages/graphviz.php @@ -0,0 +1,75 @@ +p("no lifecycle for this class"); + } + else + { + $aStates = MetaModel::EnumStates($sClass); + $aStimuli = MetaModel::EnumStimuli($sClass); + $sDotFileContent .= "digraph finite_state_machine { + rankdir=LR; + size=\"12,12\" + node [ fontname=Verdana ]; + edge [ fontname=Verdana ]; +"; + $aStatesLinks = array(); + foreach ($aStates as $sStateCode => $aStateDef) + { + $aStatesLinks[$sStateCode] = array('in' => 0, 'out' => 0); + } + + foreach ($aStates as $sStateCode => $aStateDef) + { + $sStateLabel = $aStates[$sStateCode]['label']; + $sStateDescription = $aStates[$sStateCode]['description']; + foreach(MetaModel::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef) + { + $aStatesLinks[$sStateCode]['out']++; + $aStatesLinks[$aTransitionDef['target_state']]['in']++; + $sStimulusLabel = $aStimuli[$sStimulusCode]->Get('label'); + $sTargetStateLabel = $aStates[$aTransitionDef['target_state']]['label']; + $sDotFileContent .= "\t$sStateCode -> {$aTransitionDef['target_state']} [ label=\"$sStimulusLabel\"];\n"; + } + } + foreach($aStates as $sStateCode => $aStateDef) + { + $sStateLabel = str_replace(' ', '\n', $aStates[$sStateCode]['label']); + if ( ($aStatesLinks[$sStateCode]['in'] == 0) || ($aStatesLinks[$sStateCode]['out'] == 0)) + { + $sDotFileContent .= "\t$sStateCode [ shape=doublecircle,label=\"$sStateLabel\"];\n"; + } + else + { + $sDotFileContent .= "\t$sStateCode [ shape=circle,label=\"$sStateLabel\"];\n"; + } + } + $sDotFileContent .= "}\n"; + } + return $sDotFileContent; +} + +$sClass = utils::ReadParam('class', 'bizIncidentTicket'); +$sDotDescription = GraphvizLifecycle($sClass); +$sDotFilePath = "F:/iTop/roots/81-iTop/tmp/fsm.dot"; +$rFile = fopen($sDotFilePath, "w"); +fwrite($rFile, $sDotDescription); +fclose($rFile); + +header('Content-type: image/png'); +passthru("F:/iTop/Graphviz/bin/dot.exe -Tpng < $sDotFilePath"); +?> diff --git a/pages/incident.php b/pages/incident.php new file mode 100644 index 000000000..bea0a8951 --- /dev/null +++ b/pages/incident.php @@ -0,0 +1,757 @@ +m_sCurrentStep = $sStep; + } + + protected function GetFields($sStep = '') + { + if ($sStep == '') + { + $sStep = $this->m_sCurrentStep; + } + return $this->m_aSteps[$sStep]; + } + + protected function AddContextToForm(web_page $oPage) + { + // Store as hidden fields in the page all the variables from the previous steps + foreach($this->m_aSteps as $sStep => $aFields) + { + if ($sStep == $this->m_sCurrentStep) continue; + foreach($aFields as $sAttName => $sFieldName) + { + $oPage->add("\n"); + } + } + } + + function GetObjectPicker(web_page $oPage, $sTitle, $sFieldName, $sClass) + { + $sScript = +<< 0) + { + aRelatedObjectIds = sRelatedObjectIds.split(' '); + } + else + { + aRelatedObjectIds = new Array(); + aRelatedObjectIds[0] = 0; + } + var sibusql = sClass+": pkey IN {" + aRelatedObjectIds.join(", ") + "}"; + $.get("ajax.render.php?filter=" + sibusql + "&style=list&encoding=sibusql", + { operation: "ajax" }, + function(data){ + $("#related_objects").empty(); + $("#related_objects").append(data); + $("#related_objects").removeClass("loading"); + }); + } + + function AddObject(sClass) + { + var sRelatedObjectIds = new String($('#related_object_ids').val()); + var sCurrentObjectId = new String($('#ac_current_object_id').val()); + if (sRelatedObjectIds.length > 0) + { + aRelatedObjectIds = sRelatedObjectIds.split(' '); + } + else + { + aRelatedObjectIds = new Array(); + } + // To do: check if the ID is not already in the list... + aRelatedObjectIds[aRelatedObjectIds.length] = sCurrentObjectId; + // Update the form & reload the list + $('#related_object_ids').val(aRelatedObjectIds.join(' ')); + UpdateObjectList(sClass); + } + + function ManageObjects(sTitle, sClass, sInputId) + { + $('#Manage_DlgTitle').text(sTitle); + sObjList = new String($('#'+sInputId).val()); + if (sObjList == '') + { + sObjList = new String('0'); + } + var aObjList = sObjList.split(' '); + Manage_LoadSelect('selected_objects', sClass+': pkey IN {' + aObjList.join(', ') + '}'); + Manage_LoadSelect('available_objects', sClass); + $('#ManageObjectsDlg').jqmShow(); + } + + function Manage_LoadSelect(sSelectedId, sFilter) + { + $('#'+sSelectedId).addClass('loading'); + $.get('ajax.render.php?filter=' + sFilter, + { operation: 'combo_options' }, + function(data){ + $('#'+sSelectedId).empty(); + $('#'+sSelectedId).append(data); + $('#'+sSelectedId).removeClass('loading'); + } + ); + } + + function Manage_SwapSelectedObjects(oSourceSelect, oDestinationSelect) + { + for (i=oSourceSelect.length-1;i>=0;i--) // Count down because we are removing the indexes from the combo + { + if (oSourceSelect.options[i].selected) + { + var newOption = document.createElement('option'); + newOption.text = oSourceSelect.options[i].text; + newOption.value = oSourceSelect.options[i].value; + oDestinationSelect.add(newOption, null); + oSourceSelect.remove(i); + } + } + Manage_UpdateButtons(); + } + + function Manage_UpdateButtons() + { + var oSrc = document.getElementById('available_objects'); + var oAddBtn = document.getElementById('btn_add_objects') + var oDst = document.getElementById('selected_objects'); + var oRemoveBtn = document.getElementById('btn_remove_objects') + if (oSrc.selectedIndex == -1) + { + oAddBtn.disabled = true; + } + else + { + oAddBtn.disabled = false; + } + if (oDst.selectedIndex == -1) + { + oRemoveBtn.disabled = true; + } + else + { + oRemoveBtn.disabled = false; + } + } + + function Manage_AddObjects() + { + var oSrc = document.getElementById('available_objects'); + var oDst = document.getElementById('selected_objects'); + Manage_SwapSelectedObjects(oSrc, oDst); + } + + function Manage_RemoveObjects() + { + var oSrc = document.getElementById('selected_objects'); + var oDst = document.getElementById('available_objects'); + Manage_SwapSelectedObjects(oSrc, oDst); + } + + function Manage_Ok(sClass) + { + var objectsToAdd = document.getElementById('selected_objects'); + var aSelectedObjects = new Array(); + for (i=0; i

Selected Objects

+ + + + + + + + + +
+

Selected objects:

+ +

+
+

+

+
+

Available objects:

+ +

+
+       +
+EOF; + $sHTML = ' + +   +  '; + $sHTML .= ''; + $sHTML .= '
'.$sManageObjectsDlg.'
'; + $oPage->add_script($sScript); + $oPage->add_ready_script("\$('#current_object_id').autocomplete('./ajax.render.php', { minChars:3, onItemSelect:selectItem, onFindValue:findValue, formatItem:formatItem, autoFill:true, keyHolder:'#ac_current_object_id', extraParams:{operation:'link', sclass:'$sClass', attCode:'name'}});"); + $oPage->add_ready_script("$('#ManageObjectsDlg').jqm({overlay:70, modal:true, toTop:true});"); // jqModal Window + $oPage->add_ready_script("UpdateObjectList('$sClass');"); + return $sHTML; + } + + function DisplayObjectPickerList(web_page $oPage, $sClass) + { + $oFilter = new CMDBSearchFilter($sClass); + $oFilter->AddCondition('pkey', array(0), 'IN'); + //$oPage->p($oFilter->__DescribeHTML()); + $oBlock = new DisplayBlock($oFilter, 'list', true /* Asynchronous */); + $oBlock->Display($oPage, 'related_objects'); + } +} + +class IncidentCreationWizard extends DialogWizard +{ + public function __construct($sStep) + { + parent::__construct($sStep); + $this->m_aSteps = + array( + '1' => array('title' => 'attr_title', 'customer_id' => 'attr_customer_id', 'initial_situation' => 'attr_initial_situation', 'severity' => 'attr_severity', 'impact' => 'attr_impact', 'workgroup_id' => 'attr_workgroup_id', 'action_log' => 'attr_action_log'), + '2' => array('impacted_infra_ids' => 'impacted_infra_ids'), + '3' => array('additional_impacted_object_ids' => 'additional_impacted_object_ids'), + '4' => array('related_incident_ids' => 'related_incident_ids'), + '5' => array('contact_ids' => 'contact_ids'), + ); + } + + protected function AddContextToForm($oPage) + { + parent::AddContextToForm($oPage); + $oPage->add("\n"); + $oPage->add("m_sNextStep."\" />\n"); + } + + public function DisplayNewTicketForm(web_page $oPage) + { + assert($this->m_sCurrentStep == '1'); + $this->m_sNextStep = '2'; + $aFields = $this->GetFields(); + + $oPage->add('
'); + $aDetails = array(); + $aAttributesDef = MetaModel::ListAttributeDefs('bizIncidentTicket'); + foreach($aFields as $sAttCode => $sFieldName) + { + $oAttDef = $aAttributesDef[$sAttCode]; + $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, 'bizIncidentTicket', $sAttCode, $oAttDef); + $aDetails[] = array('label' => $oAttDef->GetLabel().' *', 'value' => $sHTMLValue); + } + $oPage->details($aDetails); + $this->AddContextToForm($oPage); + $oPage->add("    \n"); + $oPage->add("\n"); + $oPage->add('
'); + } + + public function DisplayImpactedInfraForm(web_page $oPage) + { + assert($this->m_sCurrentStep == '2'); + $this->m_sNextStep = '3'; + $oPage->add('
'); + $aDetails = array(); + $sHTML = $this->GetObjectPicker($oPage, 'Impacted Infrastructure', 'impacted_infra_ids', 'logInfra'); + $aDetails[] = array('label' => 'Impacted element:', 'value' => $sHTML); + $oPage->details($aDetails); + $this->DisplayObjectPickerList($oPage, 'logInfra'); + $this->AddContextToForm($oPage); + $oPage->add("    \n"); + $oPage->add("\n"); + $oPage->add('
'); + } + + public function DisplayAdditionalImpactedObjectForm(web_page $oPage) + { + assert($this->m_sCurrentStep == '3'); + $this->m_sNextStep = '4'; + $sImpactedInfraIds = Utils::ReadParam('impacted_infra_ids'); + + $sImpactedInfraIds = Utils::ReadParam('impacted_infra_ids', ''); + if (!empty($sImpactedInfraIds)) + { + $oPage->p('Impacted Infrastructure:'); + $oFilter = new CMDBSearchFilter('logRealObject'); + $oFilter->AddCondition('pkey', explode(' ', $sImpactedInfraIds), 'IN'); + $oBlock = new DisplayBlock($oFilter, 'list', false /* Synchronous */); + $oBlock->Display($oPage, 'impacted_infra'); + } + + $aImpactedInfraIds = explode(' ', $sImpactedInfraIds); + $oInfraSet = CMDBObjectSet::FromScratch('logRealObject'); + foreach($aImpactedInfraIds as $id) + { + $oObj = MetaModel::GetObject('logRealObject', $id); + $oInfraSet->AddObject($oObj); + } + $aImpactedObject = $oInfraSet->GetRelatedObjects('impacts'); + $aAdditionalIds = array(); + foreach($aImpactedObject as $sRootClass => $aObjects) + { + foreach($aObjects as $oObj) + { + $aAdditionalIds[] = $oObj->GetKey(); + } + } + $sAdditionalIds = implode(' ', $aAdditionalIds); + $oPage->add_ready_script('$("#related_object_ids").val("'.$sAdditionalIds.'");'); + + $oPage->p('Additional Impact Computed:'); + $this->DisplayObjectPickerList($oPage, 'logRealObject'); + $oPage->add('
'); + $aDetails = array(); + $sHTML = $this->GetObjectPicker($oPage, 'Additional Impacted Infrastructure', 'additional_impacted_object_ids', 'logRealObject'); + $aDetails[] = array('label' => 'Impacted element:', 'value' => $sHTML); + $oPage->details($aDetails); + $this->AddContextToForm($oPage); + $oPage->add("    \n"); + $oPage->add("\n"); + $oPage->add('
'); + } + + public function DisplayRelatedTicketsForm(web_page $oPage) + { + assert($this->m_sCurrentStep == '4'); + $this->m_sNextStep = '5'; + $oRelatedTicketsFilter = new DBObjectSearch('bizIncidentTicket'); + $sImpactedInfraIds = Utils::ReadParam('impacted_infra_ids', ''); + $sAdditionalImpactedObjectIds = Utils::ReadParam('additional_impacted_object_ids', ''); + $sIds = trim($sImpactedInfraIds.' '.$sAdditionalImpactedObjectIds); + $aTicketIds = array(); + if (!empty($sIds)) + { + $aIds = explode(' ', $sIds); + $sSibusQL = "bizIncidentTicket: PKEY IS ticket_id IN (lnkInfraTicket: infra_id IN (logRealObject: pkey IN {".implode(',', $aIds)."}))"; + $oTicketSearch = DBObjectSearch::FromSibusQL($sSibusQL); + $oRelatedTicketSet = new DBObjectSet($oTicketSearch); + while ($oTicket = $oRelatedTicketSet->Fetch()) + { + $aTicketIds[] = $oTicket->GetKey(); + } + } + + $sTicketIds = implode(' ', $aTicketIds); + $oPage->add_ready_script('$("#related_object_ids").val("'.$sTicketIds.'");'); + $oPage->p('Potentially related incidents:'); + $this->DisplayObjectPickerList($oPage, 'bizIncidentTicket'); + + $oPage->add('
'); + $sHTML = $this->GetObjectPicker($oPage, 'Related Incidents', 'related_incident_ids', 'bizIncidentTicket'); + $aDetails[] = array('label' => 'Related Incident:', 'value' => $sHTML); + $oPage->details($aDetails); + $this->AddContextToForm($oPage); + $oPage->add("    \n"); + $oPage->add("\n"); + $oPage->add('
'); + } + + public function DisplayContactsToNotifyForm(web_page $oPage) + { + assert($this->m_sCurrentStep == '5'); + $this->m_sNextStep = '6'; + $oPage->add('
'); + $sHTML = $this->GetObjectPicker($oPage, 'Contacts to notify', 'contact_ids', 'bizContact'); + $aDetails[] = array('label' => 'Additional contact:', 'value' => $sHTML); + $oPage->details($aDetails); + $this->DisplayObjectPickerList($oPage, 'bizContact'); + $this->AddContextToForm($oPage); + $oPage->add("    \n"); + $oPage->add("\n"); + $oPage->add('
'); + } + + function DisplayFinalForm(web_page $oPage) + { + $oAppContext = new ApplicationContext(); + assert($this->m_sCurrentStep == '6'); + $this->m_sNextStep = '7'; + + $aDetails = array(); + $aAttributesDef = MetaModel::ListAttributeDefs('bizIncidentTicket'); + $aFields = $this->GetFields('1'); + foreach($aFields as $sAttCode => $sFieldName) + { + $oAttDef = $aAttributesDef[$sAttCode]; + $sValue = Utils::ReadParam($sFieldName, ''); + if ($oAttDef->IsExternalKey() && isset($sValue) && ($sValue != 0)) + { + $oTargetObj = MetaModel::GetObject($oAttDef->GetTargetClass(), $sValue); + if (!is_object($oTargetObj)) + { + trigger_error("Houston: could not find ".$oAttDef->GetTargetClass()."::$sValue"); + } + $sPage = cmdbAbstractObject::ComputeUIPage($oAttDef->GetTargetClass()); + $sHint = htmlentities($oAttDef->GetTargetClass()."::".$sValue); + $sHTMLValue = "GetTargetClass()."&id=$sValue&".$oAppContext->GetForLink()."\" title=\"$sHint\">".$oTargetObj->GetName().""; + } + else + { + $sHTMLValue = $oAttDef->GetAsHTML($sValue); + } + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue); + } + $oPage->details($aDetails); + + $oPage->AddTabContainer('LinkedObjects'); + $oPage->SetCurrentTabContainer('LinkedObjects'); + + $sImpactedInfraIds = Utils::ReadParam('impacted_infra_ids', ''); + $sImpactedInfraIds .= ' '.Utils::ReadParam('additional_impacted_object_ids', ''); + $sImpactedInfraIds = trim($sImpactedInfraIds); + $oPage->SetCurrentTab("Infrastructure impacted"); + if (!empty($sImpactedInfraIds)) + { + $oFilter = new CMDBSearchFilter('logRealObject'); + $oFilter->AddCondition('pkey', explode(' ', $sImpactedInfraIds), 'IN'); + $oBlock = new DisplayBlock($oFilter, 'list', false /* Synchronous */); + $oBlock->Display($oPage, 'related_objects'); + } + else + { + $oPage->p("There is no infrastructure impacted by this incident"); + } + + $sRelatedIncidentIds = Utils::ReadParam('related_incident_ids', ''); + $oPage->SetCurrentTab("Related tickets"); + if (!empty($sRelatedIncidentIds)) + { + $oFilter = new CMDBSearchFilter('bizIncidentTicket'); + $oFilter->AddCondition('pkey', explode(' ', $sRelatedIncidentIds), 'IN'); + $oBlock = new DisplayBlock($oFilter, 'list', false /* Synchronous */); + $oBlock->Display($oPage, 'related_incidents'); + } + else + { + $oPage->p("There is no other incident related to this one"); + } + + $oPage->SetCurrentTab("Contacts to notify"); + $sContactIds = Utils::ReadParam('contact_ids', ''); + if (!empty($sContactIds)) + { + $oFilter = new CMDBSearchFilter('bizContact'); + $oFilter->AddCondition('pkey', explode(' ', $sContactIds), 'IN'); + $oBlock = new DisplayBlock($oFilter, 'list', false /* Synchronous */); + $oBlock->Display($oPage, 'contacts'); + } + else + { + $oPage->p("There is no contact to notify"); + } + $oPage->SetCurrentTab(); + + $oPage->add('
'); + $this->AddContextToForm($oPage); + $oPage->add("    \n"); + $oPage->add("    \n"); + $oPage->add("\n"); + $oPage->add('
'); + } + + public function CreateIncident(web_page $oPage) + { + $oAppContext = new ApplicationContext(); + assert($this->m_sCurrentStep == '7'); + $this->m_sNextStep = '1'; + + $oIncident = MetaModel::NewObject('bizIncidentTicket'); + $oPage->p("Creation of Incident Ticket."); + + $aFields = $this->GetFields('1'); + foreach($aFields as $sAttCode => $sFieldName) + { + $sValue = Utils::ReadPostedParam($sFieldName, ''); + $oIncident->Set($sAttCode, $sValue); + } + $oIncident->Set('ticket_status', 'New'); + $oIncident->Set('start_date', time()); + $oIncident->Set('name', 'ID not set'); + + if ($oIncident->CheckToInsert()) + { + // Create the ticket itself + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Administrator"); + $iChangeId = $oMyChange->DBInsert(); + $oIncident->DBInsertTracked($oMyChange); + + $sName = sprintf('I-%06d', $oIncident->GetKey()); + $oIncident->Set('name', $sName); + $oIncident->DBUpdateTracked($oMyChange); + $oPage->p("Incident $sName created.\n"); + + // Now link the objects to the Incident: + // 1) the impacted infra + $sImpactedInfraIds = Utils::ReadParam('impacted_infra_ids', ''); + $sImpactedInfraIds .= ' '.Utils::ReadParam('additional_impacted_object_ids', ''); + $sImpactedInfraIds = trim($sImpactedInfraIds); + if (!empty($sImpactedInfraIds)) + { + $aImpactedInfra = explode(' ', $sImpactedInfraIds); + foreach($aImpactedInfra as $iInfraId) + { + $oLink = MetaModel::NewObject('lnkInfraTicket'); + $oLink->Set('infra_id', $iInfraId); + $oLink->Set('ticket_id', $oIncident->GetKey()); + $oLink->Set('impact', 'automatic'); + $oLink->DBInsertTracked($oMyChange); + } + } + // 2) the related incidents + $sRelatedIncidentsIds = Utils::ReadPostedParam('related_incident_ids'); + if (!empty($sRelatedIncidentsIds)) + { + $aRelatedIncidents = explode(' ', $sRelatedIncidentsIds); + foreach($aRelatedIncidents as $iIncidentId) + { + $oLink = MetaModel::NewObject('lnkRelatedTicket'); + $oLink->Set('rel_ticket_id', $iIncidentId); + $oLink->Set('ticket_id', $oIncident->GetKey()); + $oLink->Set('impact', 'automatic'); + $oLink->DBInsertTracked($oMyChange); + } + } + // 3) the contacts to notify + $sContactsIds = Utils::ReadPostedParam('contact_ids'); + if (!empty($sContactsIds)) + { + $aContactsToNotify = explode(' ', $sContactsIds); + foreach($aContactsToNotify as $iContactId) + { + $oLink = MetaModel::NewObject('lnkContactRealObject'); + $oLink->Set('contact_id', $iContactId); + $oLink->Set('object_id', $oIncident->GetKey()); + $oLink->Set('role', 'notification'); + $oLink->DBInsertTracked($oMyChange); + } + } + $oIncident->DisplayDetails($oPage, 'bizIncidentTicket', $oIncident->GetKey()); + } + else + { + $oPage->p("Error: object can not be created!\n"); + } + } +} + + +$oContext = new UserContext(); +$oAppContext = new ApplicationContext(); +$currentOrganization = utils::ReadParam('org_id', ''); +$operation = utils::ReadParam('operation', ''); +$oP = new iTopWebPage("ITop - Incident Management", $currentOrganization); + +switch($operation) +{ + case 'details': + $sClass = utils::ReadParam('class', ''); + $id = utils::ReadParam('id', ''); + if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid ! + { + $oP->add("

'class' and 'id' parameters must be specifed for this operation.

\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $id); + if ($oObj != null) + { + $oP->set_title("iTop - ".$oObj->GetName()." - $sClass details"); + $oObj->DisplayDetails($oP); + } + else + { + $oP->set_title("iTop - Error"); + $oP->add("

Sorry this object does not exist (or you are not allowed to view it).

\n"); + } + } + break; + + case 'new': + $step = utils::ReadParam('step', '1'); + $aSteps = array( + 'Ticket Information', + 'Impacted Infrastructure', + 'Additional Impact', + 'Related Tickets', + 'Contacts to Notify', + 'Confirmation', + 'Ticket Creation' + ); + $oWizard = new IncidentCreationWizard($step); + $oP = new iTopWizardWebPage("ITop - Incident Management", $currentOrganization, $step, $aSteps); + + switch($step) + { + case 1: + default: + //$oP->add(''); + $oWizard->DisplayNewTicketForm($oP); + break; + + case 2: + //$oP->add(''); + $oWizard->DisplayImpactedInfraForm($oP); + break; + + case 3: + //$oP->add(''); + $oWizard->DisplayAdditionalImpactedObjectForm($oP); + break; + + case 4: + //$oP->add(''); + $oWizard->DisplayRelatedTicketsForm($oP); + break; + + case 5: + //$oP->add(''); + $oWizard->DisplayContactsToNotifyForm($oP); + break; + + case 6: + //$oP->add(''); + $oWizard->DisplayFinalForm($oP); + break; + + case 7: + $oWizard->CreateIncident($oP); + break; + } + break; + + case 'modify': + $oP->add_linked_script("../js/json.js"); + $oP->add_linked_script("../js/forms-json-utils.js"); + $oP->add_linked_script("../js/wizardhelper.js"); + $oP->add_linked_script("../js/wizard.utils.js"); + $oP->add_linked_script("../js/linkswidget.js"); + $oP->add_linked_script("../js/jquery.blockUI.js"); + $sClass = utils::ReadParam('class', ''); + $id = utils::ReadParam('id', ''); + if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid ! + { + $oP->add("

'class' and 'id' parameters must be specifed for this operation.

\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $id); + if ($oObj != null) + { + $oP->set_title("iTop - ".$oObj->GetName()." - $sClass modification"); + $oP->add("

".$oObj->GetName()." - $sClass modification

\n"); + $oObj->DisplayModifyForm($oP); + } + else + { + $oP->set_title("iTop - Error"); + $oP->add("

Sorry this object does not exist (or you are not allowed to view it).

\n"); + } + } + break; + + case 'apply_modify': + $sClass = utils::ReadPostedParam('class', ''); + $id = utils::ReadPostedParam('id', ''); + $sTransactionId = utils::ReadPostedParam('transaction_id', ''); + if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid ! + { + $oP->add("

'class' and 'id' parameters must be specifed for this operation.

\n"); + } + else if (!utils::IsTransactionValid($sTransactionId)) + { + $oP->p("Error: object has already be updated!\n"); + } + else + { + $oObj = $oContext->GetObject($sClass, $id); + if ($oObj != null) + { + $oP->set_title("iTop - ".$oObj->GetName()." - $sClass modification"); + $oP->add("

".$oObj->GetName()." - $sClass modification

\n"); + $bObjectModified = false; + foreach(MetaModel::ListAttributeDefs(get_class($oObj)) as $sAttCode=>$oAttDef) + { + $iFlags = $oObj->GetAttributeFlags($sAttCode); + if ($iFlags & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) + { + // Non-visible, or read-only attribute, do nothing + } + else if (!$oAttDef->IsExternalField()) + { + $aAttributes[$sAttCode] = trim(utils::ReadPostedParam("attr_$sAttCode", '')); + $previousValue = $oObj->Get($sAttCode); + if (!empty($aAttributes[$sAttCode]) && ($previousValue != $aAttributes[$sAttCode])) + { + $oObj->Set($sAttCode, $aAttributes[$sAttCode]); + $bObjectModified = true; + } + } + } + if (!$bObjectModified) + { + $oP->p("No modification detected. ".get_class($oObj)." has not been updated.\n"); + } + else if ($oObj->CheckToUpdate()) + { + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by somebody"); // TO DO put the correct user info here + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBUpdateTracked($oMyChange); + + $oP->p(get_class($oObj)." updated.\n"); + } + else + { + $oP->p("Error: object can not be updated!\n"); + //$oObj->Reload(); // restore default values! + } + } + else + { + $oP->set_title("iTop - Error"); + $oP->add("

Sorry this object does not exist (or you are not allowed to edit it).

\n"); + } + } + $oP->add("

Alors ça roule ?

"); + $oObj->DisplayDetails($oP); + break; +} +$oP->output(); +?> diff --git a/pages/index.php b/pages/index.php new file mode 100644 index 000000000..33c4d77c0 --- /dev/null +++ b/pages/index.php @@ -0,0 +1,704 @@ +no_cache(); + + + +MetaModel::CheckDefinitions(); +// new API - MetaModel::DBCheckFormat(); +// not necessary, and time consuming! +// MetaModel::DBCheckIntegrity(); + + +// Comment by Rom: MetaModel::GetSubclasses("logRealObject") retourne la totale +// utiliser IsRootClass pour savoir si une classe obtenue est une classe feuille ou non +$aTopLevelClasses = array('bizService', 'bizLocation', 'bizContact', 'logInfra', 'bizDocument', 'bizObject'); + +function ReadParam($sName, $defaultValue = "") +{ + return isset($_REQUEST[$sName]) ? $_REQUEST[$sName] : $defaultValue; +} + +function DisplaySelectOrg($oPage, $sCurrentOrganization, $iContext) +{ + global $oContext; + + //$oSearchFilter = new CMDBSearchFilter("bizOrganization"); + $oSearchFilter = $oContext->NewFilter("bizOrganization"); + $oPage->p($oSearchFilter->serialize()); + $oSet = new CMDBObjectSet($oSearchFilter); + if ($oSet->Count() == 0) + { + $oPage->add("
\n"); + $oPage->add("
\n"); + $oPage->p("No organization found.\n"); + $oPage->p($oSearchFilter->__DescribeHTML()); + $oPage->add("
\n"); + $oPage->add("
\n"); + } + else + { + $oCurrentOrganization = null; + $oPage->add("
\n"); + $oPage->add("
\n"); + $oPage->add("
\n"); + $oPage->add("Select the context:\n"); + $oPage->add("\n"); + $oPage->p(""); + $oPage->add("Select an organization: \n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("
\n"); + if ($oCurrentOrganization != null) + { + $oCurrentOrganization->DisplayDetails($oPage); + } + $oPage->add("
\n"); + $oPage->add("
\n"); + } +} + +function DisplayDetails(web_page $oPage, $sClassName, $sKey) +{ + global $oContext; + //$oObj = MetaModel::GetObject($sClassName, $sKey); + $oObj = $oContext->GetObject($sClassName, $sKey); + $oPage->p("Details of ".get_class($oObj)." - $sKey"); + + $oObj->DisplayDetails($oPage); + + // Modified by rom + $aLinks = array(); + $aLinks[] = "View changes log"; + $aLinks[] = "Edit this object"; + $aLinks[] = "Delete this object (no confirmation!)"; + // By rom + foreach (MetaModel::EnumLinkingClasses($sClassName) as $sLinkClass => $aRemoteClasses) + { + foreach($aRemoteClasses as $sExtKeyAttCode => $sRemoteClass) + { + // #@# quick and dirty: guess the extkey attcode from link to current class + // later, this information should be part of the biz model + $sExtKeyToMe = ""; + foreach(MetaModel::ListAttributeDefs($sLinkClass) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsExternalKey() && $oAttDef->GetTargetClass() == $sClassName) + { + $sExtKeyToMe = $sAttCode; + break; + } + } + if (empty($sExtKeyToMe)) + { + $oPage->p("Houston... could not find the external key for $sClassName in $sLinkClass"); + } + else + { + $oFilter = new CMDBSearchFilter($sRemoteClass); // just a dummy empty one for edition + + $sButton = "
\n"; + $sButton .= "
\n"; + $aOnOKArgs = array("operation"=>"addlinks", "linkclass"=>$sLinkClass, "extkeytome"=>$sExtKeyToMe, "extkeytopartner"=>$sExtKeyAttCode); + $sButton .= dialogstack::RenderEditableField("Add links with $sRemoteClass", "filter", $oFilter->serialize(), true, "", $aOnOKArgs); + $sButton .= "
\n"; + $sButton .= "
\n"; + $aLinks[] = $sButton; + } + } + } + $sLinks = implode(" / ", $aLinks); + $oPage->p($sLinks); +} + +// By Rom +function DisplayChangesLog(web_page $oPage, $sClassName, $sKey) +{ + global $oContext; + //$oObj = MetaModel::GetObject($sClassName, $sKey); + $oObj = $oContext->GetObject($sClassName, $sKey); + $oPage->p("Changes log for ".get_class($oObj)." - $sKey"); + + $oObj->DisplayChangesLog($oPage); + + $oPage->p("View details"); + $oPage->p("Edit this object"); + $oPage->p("Delete this object (no confirmation!)"); +} + +function DumpObjectsAsCSV(web_page $oPage, $sClassName, $oSearchFilter = null, $sSeparator = ",") +{ + global $oContext; + + $aHeader = array(); + $aHeader[] = 'pkey'; + foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode=>$oAttDef) + { + $aHeader[] = $oAttDef->GetLabel(); + } + $oPage->Add(join($sSeparator, $aHeader)."\n"); + + if ($oSearchFilter == null) + { + $oSearchFilter = $oContext->NewFilter($sClassName); + } + $oObjectSet = new CMDBObjectSet($oSearchFilter); + + while ($oObj = $oObjectSet->Fetch()) + { + $aRow = array(); + $aRow[] = $oObj->GetKey(); + foreach($oObj->GetAttributesList($sClassName) as $sAttCode) + { + $aRow[] = $oObj->GetAsCSV($sAttCode); + } + $oPage->Add(join($sSeparator, $aRow)."\n"); + } +} + +function DumpObjects(web_page $oPage, $sClassName, CMDBSearchFilter $oSearchFilter = null) +{ + global $oContext; + + if ($oSearchFilter == null) + { + //$oSearchFilter = new CMDBSearchFilter($sClassName); + $oSearchFilter = $oContext->NewFilter($sClassName); + } + $aAttribs = array(); + foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode=>$oAttDef) + { + $aAttribs['key'] = array('label' => 'key', 'description' => 'Primary Key'); + $aAttribs[$sAttCode] = array('label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription()); + } + $oObjectSet = new CMDBObjectSet($oSearchFilter); + + $aValues = array(); + while ($oObj = $oObjectSet->Fetch()) + { + $aRow['key'] = "GetKey()."\">".$oObj->GetKey().""; + foreach($oObj->GetAttributesList($sClassName) as $sAttCode) + { + $aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode); + } + $aValues[] = $aRow; + } + $oPage->table($aAttribs, $aValues); +} + +function DisplayEditForm(web_page $oPage, $sClassName, $sKey) +{ + global $oContext; + //$oObj = MetaModel::GetObject($sClassName, $sKey); + $oObj = $oContext->GetObject($sClassName, $sKey); + if ($oObj == null) + { + $oPage->p("You are not allowed to edit this object."); + return; + } + $oPage->p("Edition of ".get_class($oObj)." - $sKey\n"); + + $aDetails = array(); + $oPage->add("
\n"); + foreach(MetaModel::ListAttributeDefs(get_class($oObj)) as $sAttCode=>$oAttDef) + { + if (!$oAttDef->IsExternalField()) + { + if ($oAttDef->IsExternalKey()) + { + //External key, display a combo + $sTargetClass = $oAttDef->GetTargetClass(); + //$oFilter = new CMDBSearchFilter($sTargetClass); + $oFilter = $oContext->NewFilter($sTargetClass); + $oSet = new CMDBObjectSet($oFilter); + $sValue = "\n"; + } + else + { + $sValue = "Get($sAttCode))."\">"; + } + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sValue); + } + } + $oPage->details($aDetails); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); +} + +function DisplayCreationForm(web_page $oPage, $sClassName) +{ + global $oContext; + $oPage->p("New $sClassName\n"); + + $aDetails = array(); + $oPage->add("\n"); + foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode=>$oAttDef) + { + if (!$oAttDef->IsExternalField()) + { + if ($oAttDef->IsExternalKey()) + { + //External key, display a combo + $sTargetClass = $oAttDef->GetTargetClass(); + //$oFilter = new CMDBSearchFilter($sTargetClass); + $oFilter = $oContext->NewFilter($sTargetClass); + $oSet = new CMDBObjectSet($oFilter); + $sValue = "\n"; + } + else + { + $sValue = "GetDefaultValue()."\">"; + } + $aDetails[] = array('label' => $oAttDef->GetLabel(), 'value' => $sValue); + } + } + $oPage->details($aDetails); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); +} + +function UpdateObject(web_page $oPage, $sClassName, $sKey, $aAttributes) +{ + global $oContext; + //$oObj = MetaModel::GetObject($sClassName, $sKey); + $oObj = $oContext->GetObject($sClassName, $sKey); + if ($oObj == null) + { + $oPage->p("You are not allowed to edit this object."); + return; + } + $oPage->p("Update of $sClassName - $sKey"); + + foreach(MetaModel::ListAttributeDefs(get_class($oObj)) as $sAttCode=>$oAttDef) + { + if (isset($aAttributes[$sAttCode])) + { + $oObj->Set($sAttCode, $aAttributes[$sAttCode]); + } + } + if ($oObj->CheckToUpdate()) + { + // By rom + // $oObj->DBUpdate(); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by somebody"); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBUpdateTracked($oMyChange); + + $oPage->p(get_class($oObj)." updated\n"); + } + else + { + $oPage->p("Error: object can not be updated!\n"); + $oObj->DBRevert(); // restore default values! + } + // By Rom + // $oObj->DisplayDetails($oPage); + // replaced by... + DisplayDetails($oPage, get_class($oObj), $oObj->GetKey()); + $oPage->p("Return to main page"); +} + +function DeleteObject(web_page $oPage, $sClassName, $sKey) +{ + global $oContext; + //$oObj = MetaModel::GetObject($sClassName, $sKey); + $oObj = $oContext->GetObject($sClassName, $sKey); + if ($oObj == null) + { + $oPage->p("You are not allowed to delete this object."); + return; + } + $oPage->p("Deletion of $sClassName - $sKey"); + + if ($oObj->CheckToDelete()) + { + // By Rom + //$oObj->DBDelete(); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by somebody"); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBDeleteTracked($oMyChange); + + $oPage->p("$sClassName deleted\n"); + } + else + { + $oPage->p("Error: object can not be deleted!\n"); + // By Rom + DisplayDetails($oPage, get_class($oObj), $oObj->GetKey()); + } + $oPage->p("Return to main page"); +} + +function CreateObject(web_page $oPage, $sClassName, $aAttributes) +{ + $oObj = MetaModel::NewObject($sClassName); + $oPage->p("Creation of ".get_class($oObj)." object."); + + foreach(MetaModel::ListAttributeDefs(get_class($oObj)) as $sAttCode=>$oAttDef) + { + if (isset($aAttributes[$sAttCode])) + { + $oObj->Set($sAttCode, $aAttributes[$sAttCode]); + } + } + if ($oObj->CheckToInsert()) + { + // By rom + // $oObj->DBInsert(); + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by somebody"); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBInsertTracked($oMyChange); + + $oPage->p(get_class($oObj)." created\n"); + + // By Rom + // $oObj->DisplayDetails($oPage); + // replaced by... + DisplayDetails($oPage, get_class($oObj), $oObj->GetKey()); + } + else + { + $oPage->p("Error: object can not be created!\n"); + } + $oPage->p("Return to main page"); +} + +// By Rom +function AddLinks($oPage, $sClassName, $sKey, $sLinkClass, $sExtKeyToMe, $sExtKeyToPartner, $sFilter) +{ + global $oContext; + //$oObj = MetaModel::GetObject($sClassName, $sKey); + $oObj = $oContext->GetObject($sClassName, $sKey); + if ($oObj == null) + { + $oPage->p("You are not allowed to modify (create links on) this object."); + return; + } + $oPage->p("Creating links for $sClassName - $sKey"); + + $oFilter = CMDBSearchFilter::unserialize($sFilter); + $oPage->p("Linking to ".$oFilter->__DescribeHTML()); + + $oObjSet = new CMDBObjectSet($oFilter); + if ($oObjSet->Count() != 0) + { + while($oPartnerObj = $oObjSet->Fetch()) + { + $oNewLink = MetaModel::NewObject($sLinkClass); + $oNewLink->Set($sExtKeyToMe, $sKey); + $oNewLink->Set($sExtKeyToPartner, $oPartnerObj->GetKey()); + if ($oNewLink->CheckToInsert()) + { + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by somebody"); + $iChangeId = $oMyChange->DBInsert(); + $oNewLink->DBInsertTracked($oMyChange); + + $oPage->p(get_class($oNewLink)." created\n"); + } + else + { + $oPage->p("Error: link can not be created!\n"); + } + } + } + else + {} + +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// M a i n P r o g r a m +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +$operation = ReadParam('operation', ''); +$iContext = ReadParam('ctx', 1); + +$oContext = new UserContext(); + +switch($iContext) +{ + case 2: // See only the organization 'ITOP' + $oContext->AddCondition('bizOrganization', 'pkey', 'ITOP', '='); + $oContext->AddCondition('logRealObject', 'organization', 'ITOP', '='); + break; + + case 3: // See only the organization containing 'o' and contacts containing +33 + $oContext->AddCondition('Organization', 'name', 'o', 'Contains'); + //$oContext->AddCondition('Object', 'orgname', 'o', 'Contains'); + $oContext->AddCondition('Contact', 'phone', '+33', 'Contains'); + break; + + case 1: // No limitation + default: + // nothing to do +} + +dialogstack::DeclareCaller("Main navigation menu"); + +switch($operation) +{ + case 'details': + $sClass = ReadParam('class'); + $sKey = ReadParam('key'); + DisplayDetails($oPage, $sClass, $sKey); + break; + + // By rom + case 'changeslog': + $sClass = ReadParam('class'); + $sKey = ReadParam('key'); + DisplayChangesLog($oPage, $sClass, $sKey); + break; + + case 'edit': + $sClass = ReadParam('class'); + $sKey = ReadParam('key'); + DisplayEditForm($oPage, $sClass, $sKey); + break; + + case 'update': + $sClass = ReadParam('class'); + $sKey = ReadParam('key'); + $aAttributes = ReadParam('attr', array()); + UpdateObject($oPage, $sClass, $sKey, $aAttributes); + break; + + case 'new': + $sClass = ReadParam('class'); + DisplayCreationForm($oPage, $sClass); + break; + + case 'create': + $sClass = ReadParam('class'); + $aAttributes = ReadParam('attr', array()); + CreateObject($oPage, $sClass, $aAttributes); + break; + + case 'delete': + $sClass = ReadParam('class'); + $sKey = ReadParam('key'); + DeleteObject($oPage, $sClass, $sKey); + break; + + case 'direct': + $sFilter = ReadParam('filter'); + $sFormat = ReadParam('format', 'html'); + $oSearchFilter = CMDBSearchFilter::unserialize($sFilter); + switch($sFormat) + { + case 'csv': + $oPage->small_p($oSearchFilter->__DescribeHTML()); + $oPage->Add(""); + break; + + case 'xls': + $oPage->add_header('Content-disposition: attachment;filename=served.xls'); // Will fool Excel + $oPage->add_header('Content-Type: application/vnd.ms-excel'); // Will fool Excel + DumpObjects($oPage, $oSearchFilter->GetClass(), $oSearchFilter); + break; + + case 'html': + default: + $oSet = new CMDBObjectSet($oSearchFilter); + cmdbAbstractObject::DisplaySet($oPage, $oSet); + } + break; + + case 'addlinks': + $sClass = ReadParam('class'); + $sKey = ReadParam('key'); + $sLinkClass = ReadParam('linkclass'); + $sExtKeyToMe = ReadParam('extkeytome'); + $sExtKeyToPartner = ReadParam('extkeytopartner'); + $sFilter = ReadParam('filter'); + AddLinks($oPage, $sClass, $sKey, $sLinkClass, $sExtKeyToMe, $sExtKeyToPartner, $sFilter); + break; + + default: + $sCurrentOrganization = ReadParam('org', ''); + $sActiveTab = ReadParam('classname', ''); + DisplaySelectOrg($oPage, $sCurrentOrganization, $iContext); + if ($sCurrentOrganization != "") + { + $oPage->add("
\n"); + $oPage->add("
    \n"); + $index = 1; + $iActiveTabIndex = 1; // By default the first tab is the active one + foreach( $aTopLevelClasses as $sClassName) + { + if ($sClassName == $sActiveTab) + { + $iActiveTabIndex = $index; + } + $oPage->add("\t
  • $sClassName
  • \n"); + $index++; + } + $oPage->add("
\n"); + foreach( $aTopLevelClasses as $sClassName) + { + $oPage->add("
"); + if (count(MetaModel::GetSubclasses($sClassName)) > 0) + { + $sActiveSubclass = ReadParam('subclassname', ''); + foreach(MetaModel::GetSubclasses($sClassName) as $sSubclassName) + { + //$oSearchFilter = new CMDBSearchFilter($sSubclassName); + $oSearchFilter = $oContext->NewFilter($sSubclassName); + $oSearchFilter ->AddCondition('org_id', $sCurrentOrganization, '='); + + $oPage->add("
\n"); + $oPage->add("
\n"); + $oPage->p("$sSubclassName - ".MetaModel::GetClassDescription($sSubclassName)); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + foreach( MetaModel::GetClassFilterDefs($sSubclassName) as $sFilterCode=>$oFilterDef) + { + $sFilterValue = ""; + if (($sActiveTab == $sClassName) && ($sActiveSubclass == $sSubclassName)) + { + $sFilterValue = ReadParam($sFilterCode, ''); + if (!empty($sFilterValue)) + { + $oSearchFilter->AddCondition($sFilterCode, $sFilterValue, 'Contains'); + } + } + $oPage->add($oFilterDef->GetLabel().":  \n"); + } + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("
\n"); + + $oSet = new CMDBObjectSet($oSearchFilter); + $iMatchesCount = $oSet->Count(); + if ($iMatchesCount == 0) + { + $oPage->p("No $sSubclassName matches these criteria."); + $oPage->small_p("(".$oSearchFilter->__DescribeHTML().")"); + } + else + { + $oPage->p("$iMatchesCount item(s) found."); + cmdbAbstractObject::DisplaySet($oPage, $oSet); + } + $oPage->p("Create a new $sSubclassName\n"); + $oPage->add("
\n"); + } + } + else + { + // No subclasses, list the form directly + //$oSearchFilter = new CMDBSearchFilter($sClassName); + $oSearchFilter = $oContext->NewFilter($sClassName); + $oSearchFilter ->AddCondition('org_id', $sCurrentOrganization, '='); + + $oPage->add("
\n"); + $oPage->add("
\n"); + $oPage->p("$sClassName - ".MetaModel::GetClassDescription($sClassName)); + $oPage->add("
\n"); + $oPage->add("\n"); + $oPage->add("\n"); + $oPage->add("\n"); + foreach( MetaModel::GetClassFilterDefs($sClassName) as $sFilterCode=>$oFilterDef) + { + $sFilterValue = ""; + if ($sActiveTab == $sClassName) + { + $sFilterValue = ReadParam($sFilterCode, ''); + if (!empty($sFilterValue)) + { + $oSearchFilter->AddCondition($sFilterCode, $sFilterValue, 'Contains'); + } + } + $oPage->add($oFilterDef->GetLabel().":  \n"); + } + $oPage->add("\n"); + $oPage->add("
\n"); + $oPage->add("
\n"); + $oPage->add("
\n"); + $oSet = new CMDBObjectSet($oSearchFilter); + $iMatchesCount = $oSet->Count(); + if ($iMatchesCount == 0) + { + $oPage->p("No $sClassName matches these criteria."); + $oPage->small_p("(".$oSearchFilter->__DescribeHTML().")"); + } + else + { + $oPage->p("$iMatchesCount item(s) found."); + cmdbAbstractObject::DisplaySet($oPage, $oSet); + $oPage->small_p("(".$oSearchFilter->__DescribeHTML().")"); + } + $oPage->p("Create a new $sClassName\n"); + $oPage->add("
\n"); + $oPage->add("
\n"); + } + $oPage->add("
\n"); + } + $oPage->add("
\n"); + $oPage->add_script('$(function() {$("#classesTabs > ul").tabs( '.$iActiveTabIndex.', { fxFade: true, fxSpeed: \'fast\' } );});'); + } +} +$oPage->output(); +?> diff --git a/pages/opensearch.xml b/pages/opensearch.xml new file mode 100644 index 000000000..2620b2d1f --- /dev/null +++ b/pages/opensearch.xml @@ -0,0 +1,8 @@ + +iTop +webmaster@itop.com +Recherche dans iTop +ISO-8859-1 + +http://localhost:81/pages/UI.php + \ No newline at end of file diff --git a/pages/php-ofc-library/JSON.php b/pages/php-ofc-library/JSON.php new file mode 100644 index 000000000..7260001a2 --- /dev/null +++ b/pages/php-ofc-library/JSON.php @@ -0,0 +1,806 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 3); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 5); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_SUPPRESS_ERRORS', 32); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); + + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } +} + +if (class_exists('PEAR_Error')) { + + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } + +} else { + + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } + +} + +?> diff --git a/pages/php-ofc-library/README.txt b/pages/php-ofc-library/README.txt new file mode 100644 index 000000000..2d8b6297f --- /dev/null +++ b/pages/php-ofc-library/README.txt @@ -0,0 +1,16 @@ +Open Flash Chart - PHP libraries. These help create data files for Open Flash Chart. +Copyright (C) 2007 + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file diff --git a/pages/php-ofc-library/json_format.php b/pages/php-ofc-library/json_format.php new file mode 100644 index 000000000..61a842ea1 --- /dev/null +++ b/pages/php-ofc-library/json_format.php @@ -0,0 +1,86 @@ + 0 && $json[$c-1] != '\\') + { + $in_string = !$in_string; + } + default: + $new_json .= $char; + break; + } + } + + return $new_json; +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_area_base.php b/pages/php-ofc-library/ofc_area_base.php new file mode 100644 index 000000000..8d8f7560a --- /dev/null +++ b/pages/php-ofc-library/ofc_area_base.php @@ -0,0 +1,66 @@ +$tmp = 0.35; + $this->values = array(); + } + + function set_width( $w ) + { + $this->width = $w; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_fill_colour( $colour ) + { + $this->fill = $colour; + } + + function set_fill_alpha( $alpha ) + { + $tmp = "fill-alpha"; + $this->$tmp = $alpha; + } + + function set_halo_size( $size ) + { + $tmp = 'halo-size'; + $this->$tmp = $size; + } + + function set_values( $v ) + { + $this->values = $v; + } + + function set_dot_size( $size ) + { + $tmp = 'dot-size'; + $this->$tmp = $size; + } + + function set_key( $text, $font_size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + function set_loop() + { + $this->loop = true; + } +} diff --git a/pages/php-ofc-library/ofc_area_hollow.php b/pages/php-ofc-library/ofc_area_hollow.php new file mode 100644 index 000000000..ba6c20461 --- /dev/null +++ b/pages/php-ofc-library/ofc_area_hollow.php @@ -0,0 +1,10 @@ +type = "area_hollow"; + parent::area_base(); + } +} diff --git a/pages/php-ofc-library/ofc_area_line.php b/pages/php-ofc-library/ofc_area_line.php new file mode 100644 index 000000000..c4b2b167e --- /dev/null +++ b/pages/php-ofc-library/ofc_area_line.php @@ -0,0 +1,10 @@ +type = "area_line"; + parent::area_base(); + } +} diff --git a/pages/php-ofc-library/ofc_bar.php b/pages/php-ofc-library/ofc_bar.php new file mode 100644 index 000000000..0666939ff --- /dev/null +++ b/pages/php-ofc-library/ofc_bar.php @@ -0,0 +1,34 @@ +top = $top; + + if( isset( $bottom ) ) + $this->bottom = $bottom; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class bar extends bar_base +{ + function bar() + { + $this->type = "bar"; + parent::bar_base(); + } +} + diff --git a/pages/php-ofc-library/ofc_bar_3d.php b/pages/php-ofc-library/ofc_bar_3d.php new file mode 100644 index 000000000..4b4d8f4fb --- /dev/null +++ b/pages/php-ofc-library/ofc_bar_3d.php @@ -0,0 +1,31 @@ +top = $top; +// $this->bottom = $bottom; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class bar_3d extends bar_base +{ + function bar_3d() + { + $this->type = "bar_3d"; + parent::bar_base(); + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_bar_base.php b/pages/php-ofc-library/ofc_bar_base.php new file mode 100644 index 000000000..4ab5c52e5 --- /dev/null +++ b/pages/php-ofc-library/ofc_bar_base.php @@ -0,0 +1,41 @@ +text = $text; + $tmp = 'font-size'; + $this->$tmp = $size; + } + + function set_values( $v ) + { + $this->values = $v; + } + + function append_value( $v ) + { + $this->values[] = $v; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_alpha( $alpha ) + { + $this->alpha = $alpha; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + diff --git a/pages/php-ofc-library/ofc_bar_filled.php b/pages/php-ofc-library/ofc_bar_filled.php new file mode 100644 index 000000000..2008703cd --- /dev/null +++ b/pages/php-ofc-library/ofc_bar_filled.php @@ -0,0 +1,39 @@ +$tmp = $outline_colour; + } +} + +class bar_filled extends bar_base +{ + function bar_filled( $colour=null, $outline_colour=null ) + { + $this->type = "bar_filled"; + parent::bar_base(); + + if( isset( $colour ) ) + $this->set_colour( $colour ); + + if( isset( $outline_colour ) ) + $this->set_outline_colour( $outline_colour ); + } + + function set_outline_colour( $outline_colour ) + { + $tmp = 'outline-colour'; + $this->$tmp = $outline_colour; + } +} + diff --git a/pages/php-ofc-library/ofc_bar_glass.php b/pages/php-ofc-library/ofc_bar_glass.php new file mode 100644 index 000000000..4ca674378 --- /dev/null +++ b/pages/php-ofc-library/ofc_bar_glass.php @@ -0,0 +1,33 @@ +top = $top; +// $this->bottom = $bottom; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + + +class bar_glass extends bar_base +{ + function bar_glass() + { + $this->type = "bar_glass"; + parent::bar_base(); + } +} diff --git a/pages/php-ofc-library/ofc_bar_sketch.php b/pages/php-ofc-library/ofc_bar_sketch.php new file mode 100644 index 000000000..f39fdcfd9 --- /dev/null +++ b/pages/php-ofc-library/ofc_bar_sketch.php @@ -0,0 +1,23 @@ +type = "bar_sketch"; + parent::bar_base(); + + $this->set_colour( $colour ); + $this->set_outline_colour( $outline_colour ); + $this->offset = $fun_factor; + } + + function set_outline_colour( $outline_colour ) + { + $tmp = 'outline-colour'; + $this->$tmp = $outline_colour; + } +} + diff --git a/pages/php-ofc-library/ofc_bar_stack.php b/pages/php-ofc-library/ofc_bar_stack.php new file mode 100644 index 000000000..945d3d8aa --- /dev/null +++ b/pages/php-ofc-library/ofc_bar_stack.php @@ -0,0 +1,50 @@ +type = "bar_stack"; + parent::bar_base(); + } + + function append_stack( $v ) + { + $this->append_value( $v ); + } + + // an array of HEX colours strings + // e.g. array( '#ff0000', '#00ff00' ); + function set_colours( $colours ) + { + $this->colours = $colours; + } + + // an array of bar_stack_value + function set_keys( $keys ) + { + $this->keys = $keys; + } +} + +class bar_stack_value +{ + function bar_stack_value( $val, $colour ) + { + $this->val = $val; + $this->colour = $colour; + } +} + +class bar_stack_key +{ + function bar_stack_key( $colour, $text, $font_size ) + { + $this->colour = $colour; + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_hbar.php b/pages/php-ofc-library/ofc_hbar.php new file mode 100644 index 000000000..a0fffbb55 --- /dev/null +++ b/pages/php-ofc-library/ofc_hbar.php @@ -0,0 +1,64 @@ +left = $left; + $this->right = $right; + } + else + $this->right = $left; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class hbar +{ + function hbar( $colour ) + { + $this->type = "hbar"; + $this->values = array(); + $this->set_colour( $colour ); + } + + function append_value( $v ) + { + $this->values[] = $v; + } + + function set_values( $v ) + { + foreach( $v as $val ) + $this->append_value( new hbar_value( $val ) ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_key( $text, $size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + diff --git a/pages/php-ofc-library/ofc_line.php b/pages/php-ofc-library/ofc_line.php new file mode 100644 index 000000000..945af208e --- /dev/null +++ b/pages/php-ofc-library/ofc_line.php @@ -0,0 +1,9 @@ +type = "line"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_line_base.php b/pages/php-ofc-library/ofc_line_base.php new file mode 100644 index 000000000..2e969f9e3 --- /dev/null +++ b/pages/php-ofc-library/ofc_line_base.php @@ -0,0 +1,70 @@ +type = "line_dot"; + $this->text = "Page views"; + $tmp = 'font-size'; + $this->$tmp = 10; + + $this->values = array(9,6,7,9,5,7,6,9,7); + } + + function set_values( $v ) + { + $this->values = $v; + } + + function set_width( $width ) + { + $this->width = $width; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_dot_size( $size ) + { + $tmp = 'dot-size'; + $this->$tmp = $size; + } + + function set_halo_size( $size ) + { + $tmp = 'halo-size'; + $this->$tmp = $size; + } + + function set_key( $text, $font_size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + function set_on_click( $text ) + { + $tmp = 'on-click'; + $this->$tmp = $text; + } + + function loop() + { + $this->loop = true; + } + + function line_style( $s ) + { + $tmp = "line-style"; + $this->$tmp = $s; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_line_dot.php b/pages/php-ofc-library/ofc_line_dot.php new file mode 100644 index 000000000..52f2ad0eb --- /dev/null +++ b/pages/php-ofc-library/ofc_line_dot.php @@ -0,0 +1,33 @@ +value = $value; + $this->colour = $colour; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_size( $size ) + { + $this->size = $size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class line_dot extends line_base +{ + function line_dot() + { + $this->type = "line_dot"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_line_hollow.php b/pages/php-ofc-library/ofc_line_hollow.php new file mode 100644 index 000000000..783fdf778 --- /dev/null +++ b/pages/php-ofc-library/ofc_line_hollow.php @@ -0,0 +1,9 @@ +type = "line_hollow"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_line_style.php b/pages/php-ofc-library/ofc_line_style.php new file mode 100644 index 000000000..4ba5ff8b6 --- /dev/null +++ b/pages/php-ofc-library/ofc_line_style.php @@ -0,0 +1,11 @@ +style = "dash"; + $this->on = $on; + $this->off = $off; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_pie.php b/pages/php-ofc-library/ofc_pie.php new file mode 100644 index 000000000..be50008e5 --- /dev/null +++ b/pages/php-ofc-library/ofc_pie.php @@ -0,0 +1,109 @@ +value = $value; + $this->label = $label; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_label( $label, $label_colour, $font_size ) + { + $this->label = $label; + + $tmp = 'label-colour'; + $this->$tmp = $label_colour; + + $tmp = 'font-size'; + $this->$tmp = $font_size; + + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + function on_click( $event ) + { + $tmp = 'on-click'; + $this->$tmp = $event; + } + +} + +class pie +{ + function pie() + { + $this->type = 'pie'; + $this->colours = array("#d01f3c","#356aa0","#C79810"); + $this->border = 2; + } + + function set_colours( $colours ) + { + $this->colours = $colours; + } + + function set_alpha( $alpha ) + { + $this->alpha = $alpha; + } + + function set_values( $v ) + { + $this->values = $v; + } + + // boolean + function set_animate( $animate ) + { + $this->animate = $animate; + } + + // real + function set_start_angle( $angle ) + { + $tmp = 'start-angle'; + $this->$tmp = $angle; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + function set_gradient_fill() + { + $tmp = 'gradient-fill'; + $this->$tmp = true; + } + + function set_label_colour( $label_colour ) + { + $tmp = 'label-colour'; + $this->$tmp = $label_colour; + } + + /** + * Turn off the labels + */ + function set_no_labels() + { + $tmp = 'no-labels'; + $this->$tmp = true; + } + + function on_click( $event ) + { + $tmp = 'on-click'; + $this->$tmp = $event; + } +} diff --git a/pages/php-ofc-library/ofc_radar_axis.php b/pages/php-ofc-library/ofc_radar_axis.php new file mode 100644 index 000000000..9c8d7885f --- /dev/null +++ b/pages/php-ofc-library/ofc_radar_axis.php @@ -0,0 +1,47 @@ +set_max( $max ); + } + + function set_max( $max ) + { + $this->max = $max; + } + + function set_steps( $steps ) + { + $this->steps = $steps; + } + + function set_stroke( $s ) + { + $this->stroke = $s; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_grid_colour( $colour ) + { + $tmp = 'grid-colour'; + $this->$tmp = $colour; + } + + function set_labels( $labels ) + { + $this->labels = $labels; + } + + function set_spoke_labels( $labels ) + { + $tmp = 'spoke-labels'; + $this->$tmp = $labels; + } +} + diff --git a/pages/php-ofc-library/ofc_radar_axis_labels.php b/pages/php-ofc-library/ofc_radar_axis_labels.php new file mode 100644 index 000000000..1c4321cce --- /dev/null +++ b/pages/php-ofc-library/ofc_radar_axis_labels.php @@ -0,0 +1,15 @@ +labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_radar_spoke_labels.php b/pages/php-ofc-library/ofc_radar_spoke_labels.php new file mode 100644 index 000000000..11b6682f1 --- /dev/null +++ b/pages/php-ofc-library/ofc_radar_spoke_labels.php @@ -0,0 +1,15 @@ +labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_scatter.php b/pages/php-ofc-library/ofc_scatter.php new file mode 100644 index 000000000..978dc0487 --- /dev/null +++ b/pages/php-ofc-library/ofc_scatter.php @@ -0,0 +1,42 @@ +x = $x; + $this->y = $y; + + if( $dot_size > 0 ) + { + $tmp = 'dot-size'; + $this->$tmp = $dot_size; + } + } +} + +class scatter +{ + function scatter( $colour, $dot_size ) + { + $this->type = "scatter"; + $this->set_colour( $colour ); + $this->set_dot_size( $dot_size ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_dot_size( $dot_size ) + { + $tmp = 'dot-size'; + $this->$tmp = $dot_size; + } + + function set_values( $values ) + { + $this->values = $values; + } +} diff --git a/pages/php-ofc-library/ofc_scatter_line.php b/pages/php-ofc-library/ofc_scatter_line.php new file mode 100644 index 000000000..3c4e21c0f --- /dev/null +++ b/pages/php-ofc-library/ofc_scatter_line.php @@ -0,0 +1,27 @@ +type = "scatter_line"; + $this->set_colour( $colour ); + $this->set_dot_size( $dot_size ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_dot_size( $dot_size ) + { + $tmp = 'dot-size'; + $this->$tmp = $dot_size; + } + + function set_values( $values ) + { + $this->values = $values; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_shape.php b/pages/php-ofc-library/ofc_shape.php new file mode 100644 index 000000000..3bab90790 --- /dev/null +++ b/pages/php-ofc-library/ofc_shape.php @@ -0,0 +1,25 @@ +x = $x; + $this->y = $y; + } +} + +class shape +{ + function shape( $colour ) + { + $this->type = "shape"; + $this->colour = $colour; + $this->values = array(); + } + + function append_value( $p ) + { + $this->values[] = $p; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_title.php b/pages/php-ofc-library/ofc_title.php new file mode 100644 index 000000000..6dd19bbb8 --- /dev/null +++ b/pages/php-ofc-library/ofc_title.php @@ -0,0 +1,15 @@ +text = $text; + } + + function set_style( $css ) + { + $this->style = $css; + //"{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_tooltip.php b/pages/php-ofc-library/ofc_tooltip.php new file mode 100644 index 000000000..161a77ba0 --- /dev/null +++ b/pages/php-ofc-library/ofc_tooltip.php @@ -0,0 +1,51 @@ +shadow = $shadow; + } + + // stroke in pixels (e.g. 5 ) + function set_stroke( $stroke ) + { + $this->stroke = $stroke; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_background_colour( $bg ) + { + $this->background = $bg; + } + + // a css style + function set_title_style( $style ) + { + $this->title = $style; + } + + function set_body_style( $style ) + { + $this->body = $style; + } + + function set_proximity() + { + $this->mouse = 1; + } + + function set_hover() + { + $this->mouse = 2; + } +} + diff --git a/pages/php-ofc-library/ofc_upload_image.php b/pages/php-ofc-library/ofc_upload_image.php new file mode 100644 index 000000000..b726af946 --- /dev/null +++ b/pages/php-ofc-library/ofc_upload_image.php @@ -0,0 +1,61 @@ + save_image debug mode, you +// will see the 'echo' text in a new window. +// + +/* + +print_r( $_GET ); +print_r( $_POST ); +print_r( $_FILES ); + +print_r( $GLOBALS ); +print_r( $GLOBALS["HTTP_RAW_POST_DATA"] ); + +*/ + + +// default path for the image to be stored // +$default_path = '../tmp-upload-images/'; + +if (!file_exists($default_path)) mkdir($default_path, 0777, true); + +// full path to the saved image including filename // +$destination = $default_path . basename( $_GET[ 'name' ] ); + +echo 'Saving your image to: '. $destination; + +$jfh = fopen($destination, 'w') or die("can't open file"); +fwrite($jfh, $GLOBALS['HTTP_RAW_POST_DATA']); +fclose($jfh); + +// +// LOOK: +// +exit(); + + +// +// PHP5: +// + + +// default path for the image to be stored // +$default_path = 'tmp-upload-images/'; + +if (!file_exists($default_path)) mkdir($default_path, 0777, true); + +// full path to the saved image including filename // +$destination = $default_path . basename( $_FILES[ 'Filedata' ][ 'name' ] ); + +// move the image into the specified directory // +if (move_uploaded_file($_FILES[ 'Filedata' ][ 'tmp_name' ], $destination)) { + echo "The file " . basename( $_FILES[ 'Filedata' ][ 'name' ] ) . " has been uploaded;"; +} else { + echo "FILE UPLOAD FAILED"; +} + + +?> diff --git a/pages/php-ofc-library/ofc_x_axis.php b/pages/php-ofc-library/ofc_x_axis.php new file mode 100644 index 000000000..b268bdeb6 --- /dev/null +++ b/pages/php-ofc-library/ofc_x_axis.php @@ -0,0 +1,77 @@ +stroke = $stroke; + } + + function set_colours( $colour, $grid_colour ) + { + $this->set_colour( $colour ); + $this->set_grid_colour( $grid_colour ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tick_height( $height ) + { + $tmp = 'tick-height'; + $this->$tmp = $height; + } + + function set_grid_colour( $colour ) + { + $tmp = 'grid-colour'; + $this->$tmp = $colour; + } + + // $o is a boolean + function set_offset( $o ) + { + $this->offset = $o?true:false; + } + + function set_steps( $steps ) + { + $this->steps = $steps; + } + + function set_3d( $val ) + { + $tmp = '3d'; + $this->$tmp = $val; + } + + function set_labels( $x_axis_labels ) + { + //$this->labels = $v; + $this->labels = $x_axis_labels; + } + + // + // helper function to make the examples + // simpler. + // + function set_labels_from_array( $a ) + { + $x_axis_labels = new x_axis_labels(); + $x_axis_labels->set_labels( $a ); + $this->labels = $x_axis_labels; + + if( isset( $this->steps ) ) + $x_axis_labels->set_steps( $this->steps ); + } + + function set_range( $min, $max ) + { + $this->min = $min; + $this->max = $max; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_x_axis_label.php b/pages/php-ofc-library/ofc_x_axis_label.php new file mode 100644 index 000000000..11a79d7ed --- /dev/null +++ b/pages/php-ofc-library/ofc_x_axis_label.php @@ -0,0 +1,42 @@ +set_text( $text ); + $this->set_colour( $colour ); + $this->set_size( $size ); + $this->set_rotate( $rotate ); + } + + function set_text( $text ) + { + $this->text = $text; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_size( $size ) + { + $this->size = $size; + } + + function set_rotate( $rotate ) + { + $this->rotate = $rotate; + } + + function set_vertical() + { + $this->rotate = "vertical"; + } + + function set_visible() + { + $this->visible = true; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_x_axis_labels.php b/pages/php-ofc-library/ofc_x_axis_labels.php new file mode 100644 index 000000000..9781025ad --- /dev/null +++ b/pages/php-ofc-library/ofc_x_axis_labels.php @@ -0,0 +1,34 @@ +steps = $steps; + } + + // + // An array of [x_axis_label or string] + // + function set_labels( $labels ) + { + $this->labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_size( $size ) + { + $this->size = $size; + } + + function set_vertical() + { + $this->rotate = "vertical"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_x_legend.php b/pages/php-ofc-library/ofc_x_legend.php new file mode 100644 index 000000000..f36c017f4 --- /dev/null +++ b/pages/php-ofc-library/ofc_x_legend.php @@ -0,0 +1,15 @@ +text = $text; + } + + function set_style( $css ) + { + $this->style = $css; + //"{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_y_axis.php b/pages/php-ofc-library/ofc_y_axis.php new file mode 100644 index 000000000..c8720a192 --- /dev/null +++ b/pages/php-ofc-library/ofc_y_axis.php @@ -0,0 +1,17 @@ +$tmp = $colour; + } + +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_y_axis_base.php b/pages/php-ofc-library/ofc_y_axis_base.php new file mode 100644 index 000000000..5cfc61f15 --- /dev/null +++ b/pages/php-ofc-library/ofc_y_axis_base.php @@ -0,0 +1,56 @@ +stroke = $s; + } + + function set_tick_length( $val ) + { + $tmp = 'tick-length'; + $this->$tmp = $val; + } + + function set_colours( $colour, $grid_colour ) + { + $this->set_colour( $colour ); + $this->set_grid_colour( $grid_colour ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_grid_colour( $colour ) + { + $tmp = 'grid-colour'; + $this->$tmp = $colour; + } + + function set_range( $min, $max, $steps=1 ) + { + $this->min = $min; + $this->max = $max; + $this->set_steps( $steps ); + } + + function set_offset( $off ) + { + $this->offset = $off?1:0; + } + + function set_labels( $labels ) + { + $this->labels = $labels; + } + + function set_steps( $steps ) + { + $this->steps = $steps; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/ofc_y_axis_right.php b/pages/php-ofc-library/ofc_y_axis_right.php new file mode 100644 index 000000000..1e0911194 --- /dev/null +++ b/pages/php-ofc-library/ofc_y_axis_right.php @@ -0,0 +1,6 @@ +text = $text; + } + + function set_style( $css ) + { + $this->style = $css; + //"{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"; + } +} \ No newline at end of file diff --git a/pages/php-ofc-library/open-flash-chart-object.php b/pages/php-ofc-library/open-flash-chart-object.php new file mode 100644 index 000000000..d3b64aa48 --- /dev/null +++ b/pages/php-ofc-library/open-flash-chart-object.php @@ -0,0 +1,109 @@ +'; + + if( !isset( $open_flash_chart_seqno ) ) + { + $open_flash_chart_seqno = 1; + $out[] = ''; + } + else + { + $open_flash_chart_seqno++; + $obj_id .= '_'. $open_flash_chart_seqno; + $div_name .= '_'. $open_flash_chart_seqno; + } + + if( $use_swfobject ) + { + // Using library for auto-enabling Flash object on IE, disabled-Javascript proof + $out[] = '
'; + $out[] = ''; + $out[] = ''; + } + + return implode("\n",$out); +} +?> \ No newline at end of file diff --git a/pages/php-ofc-library/open-flash-chart.php b/pages/php-ofc-library/open-flash-chart.php new file mode 100644 index 000000000..6147da531 --- /dev/null +++ b/pages/php-ofc-library/open-flash-chart.php @@ -0,0 +1,138 @@ +title = new title( "Many data lines" ); + $this->elements = array(); + } + + function set_title( $t ) + { + $this->title = $t; + } + + function set_x_axis( $x ) + { + $this->x_axis = $x; + } + + function set_y_axis( $y ) + { + $this->y_axis = $y; + } + + function add_y_axis( $y ) + { + $this->y_axis = $y; + } + + function set_y_axis_right( $y ) + { + $this->y_axis_right = $y; + } + + function add_element( $e ) + { + $this->elements[] = $e; + } + + function set_x_legend( $x ) + { + $this->x_legend = $x; + } + + function set_y_legend( $y ) + { + $this->y_legend = $y; + } + + function set_bg_colour( $colour ) + { + $this->bg_colour = $colour; + } + + function set_radar_axis( $radar ) + { + $this->radar_axis = $radar; + } + + function set_tooltip( $tooltip ) + { + $this->tooltip = $tooltip; + } + + function toString() + { + if (function_exists('json_encode')) + { + return json_encode($this); + } + else + { + $json = new Services_JSON(); + return $json->encode( $this ); + } + } + + function toPrettyString() + { + return json_format( $this->toString() ); + } +} + + + +// +// there is no PHP end tag so we don't mess the headers up! +// \ No newline at end of file diff --git a/pages/schema.php b/pages/schema.php new file mode 100644 index 000000000..ef06f230f --- /dev/null +++ b/pages/schema.php @@ -0,0 +1,475 @@ + link to a class + */ +function MakeClassHLink($sClass) +{ + return "".MetaModel::GetName($sClass).""; +} + +/** + * Helper for this page -> link to a class + */ +function MakeRelationHLink($sRelCode) +{ + $sDec = MetaModel::GetRelationProperty($sRelCode, 'description'); + //$sVerbDown = MetaModel::GetRelationProperty($sRelCode, 'verb_down'); + //$sVerbUp = MetaModel::GetRelationProperty($sRelCode, 'verb_up'); + return "".$sRelCode.""; +} + +/** + * Helper for the global list and the details of a given class + */ +function DisplaySubclasses($oPage, $sClass) +{ + $aChildClasses = MetaModel::EnumChildClasses($sClass); + if (count($aChildClasses) != 0) + { + $oPage->add("
    \n"); + foreach($aChildClasses as $sClassName) + { + // Skip indirect childs, they will be handled somewhere else + if (MetaModel::GetParentPersistentClass($sClassName) == $sClass) + { + $oPage->add("
  • ".MakeClassHLink($sClassName)."\n"); + DisplaySubclasses($oPage, $sClassName); + $oPage->add("
  • \n"); + } + } + $oPage->add("
\n"); + } +} + +/** + * Helper for the global list and the details of a given class + */ +function DisplayReferencingClasses($oPage, $sClass) +{ + $bSkipLinkingClasses = false; + $aRefs = MetaModel::EnumReferencingClasses($sClass, $bSkipLinkingClasses); + if (count($aRefs) != 0) + { + $oPage->add("
    \n"); + foreach ($aRefs as $sRemoteClass => $aRemoteKeys) + { + foreach ($aRemoteKeys as $sExtKeyAttCode) + { + $oPage->add("
  • ".MakeClassHLink($sRemoteClass)." by $sExtKeyAttCode
  • \n"); + } + } + $oPage->add("
\n"); + } +} + +/** + * Helper for the global list and the details of a given class + */ +function DisplayLinkingClasses($oPage, $sClass) +{ + $bSkipLinkingClasses = false; + $aRefs = MetaModel::EnumLinkingClasses($sClass); + if (count($aRefs) != 0) + { + $oPage->add("
    \n"); + foreach ($aRefs as $sLinkClass => $aRemoteClasses) + { + foreach($aRemoteClasses as $sExtKeyAttCode => $sRemoteClass) + { + $oPage->add("
  • ".MakeClassHLink($sRemoteClass)." by ".MakeClassHLink($sLinkClass)."::$sExtKeyAttCode
  • \n"); + } + } + $oPage->add("
\n"); + } +} + +/** + * Helper for the global list and the details of a given class + */ +function DisplayRelatedClassesBestInClass($oPage, $sClass, $iLevels = 20, &$aVisitedClasses = array(), $bSubtree = true) +{ + if ($iLevels <= 0) return; + $iLevels--; + + if (array_key_exists($sClass, $aVisitedClasses)) return; + $aVisitedClasses[$sClass] = true; + + if ($bSubtree) $oPage->add("
    \n"); + foreach (MetaModel::EnumParentClasses($sClass) as $sParentClass) + { + DisplayRelatedClassesBestInClass($oPage, $sParentClass, $iLevels, $aVisitedClasses, false); + } + ////$oPage->add("
    "); + foreach (MetaModel::EnumReferencedClasses($sClass) as $sExtKeyAttCode => $sRemoteClass) + { + $sVisited = (array_key_exists($sRemoteClass, $aVisitedClasses)) ? " ..." : ""; + if (MetaModel::GetAttributeOrigin($sClass, $sExtKeyAttCode) == $sClass) + { + $oPage->add("
  • $sClass| $sExtKeyAttCode =>".MakeClassHLink($sRemoteClass)."$sVisited
  • \n"); + DisplayRelatedClassesBestInClass($oPage, $sRemoteClass, $iLevels, $aVisitedClasses); + } + } + foreach (MetaModel::EnumReferencingClasses($sClass) as $sRemoteClass => $aRemoteKeys) + { + foreach ($aRemoteKeys as $sExtKeyAttCode) + { + $sVisited = (array_key_exists($sRemoteClass, $aVisitedClasses)) ? " ..." : ""; + $oPage->add("
  • $sClass| <=".MakeClassHLink($sRemoteClass)."::$sExtKeyAttCode$sVisited
  • \n"); + DisplayRelatedClassesBestInClass($oPage, $sRemoteClass, $iLevels, $aVisitedClasses); + } + } + ////$oPage->add("
    "); + if ($bSubtree) $oPage->add("
\n"); +} + +/** + * Helper for the list of classes related to the given class + */ +function DisplayRelatedClasses($oPage, $sClass) +{ + $oPage->add("

Childs

\n"); + DisplaySubclasses($oPage, $sClass); + + $oPage->add("

Pointed to by...

\n"); + DisplayReferencingClasses($oPage, $sClass); + + $oPage->add("

Linked to ...

\n"); + DisplayLinkingClasses($oPage, $sClass); + + $oPage->add("

ZE Graph ...

\n"); + DisplayRelatedClassesBestInClass($oPage, $sClass, 4); +} + +/** + * Helper for the lifecycle details of a given class + */ +function DisplayLifecycle($oPage, $sClass) +{ + $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); + if (empty($sStateAttCode)) + { + $oPage->p("no lifecycle for this class"); + } + else + { + $aStates = MetaModel::EnumStates($sClass); + $aStimuli = MetaModel::EnumStimuli($sClass); + $oPage->add("\n"); + $oPage->add("

Transitions

\n"); + $oPage->add("
    \n"); + foreach ($aStates as $sStateCode => $aStateDef) + { + $sStateLabel = $aStates[$sStateCode]['label']; + $sStateDescription = $aStates[$sStateCode]['description']; + $oPage->add("
  • $sStateLabel ($sStateDescription)
  • \n"); + $oPage->add("
      \n"); + foreach(MetaModel::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef) + { + $sStimulusLabel = $aStimuli[$sStimulusCode]->Get('label'); + $sTargetStateLabel = $aStates[$aTransitionDef['target_state']]['label']; + if (count($aTransitionDef['actions']) > 0) + { + $sActions = " (".implode(', ', $aTransitionDef['actions']).")"; + } + else + { + $sActions = ""; + } + $oPage->add("
    • $sStimulusLabel => $sTargetStateLabel $sActions
    • \n"); + } + $oPage->add("
    \n"); + } + $oPage->add("
\n"); + + $oPage->add("

Attribute options

\n"); + $oPage->add("
    \n"); + foreach ($aStates as $sStateCode => $aStateDef) + { + $sStateLabel = $aStates[$sStateCode]['label']; + $sStateDescription = $aStates[$sStateCode]['description']; + $oPage->add("
  • $sStateLabel ($sStateDescription)
  • \n"); + if (count($aStates[$sStateCode]['attribute_list']) > 0) + { + $oPage->add("
      \n"); + foreach($aStates[$sStateCode]['attribute_list'] as $sAttCode => $iOptions) + { + $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); + $sAttLabel = $oAttDef->GetLabel(); + + $aOptions = array(); + if ($iOptions & OPT_ATT_HIDDEN) $aOptions[] = 'Hidden'; + if ($iOptions & OPT_ATT_READONLY) $aOptions[] = 'Read-only'; + if ($iOptions & OPT_ATT_MANDATORY) $aOptions[] = 'Mandatory'; + if ($iOptions & OPT_ATT_MUSTCHANGE) $aOptions[] = 'Must change'; + if ($iOptions & OPT_ATT_MUSTPROMPT) $aOptions[] = 'Must be proposed for changing'; + if (count($aOptions)) + { + $sOptions = implode(', ', $aOptions); + } + else + { + $sOptions = ""; + } + + $oPage->add("
    • $sAttLabel $sOptions
    • \n"); + } + $oPage->add("
    \n"); + } + else + { + $oPage->p("empty list"); + } + } + $oPage->add("
\n"); + } +} + + +/** + * Display the list of classes from the business model + */ +function DisplayClassesList($oPage) +{ + $oPage->add("

iTop objects schema

\n"); + + $oPage->add("
    \n"); + foreach(MetaModel::EnumCategories() as $sCategory) + { + if (empty($sCategory)) continue; // means 'all' -> skip + + $sClosed = ($sCategory == 'bizmodel') ? '' : ' class="closed"'; + $oPage->add("Category $sCategory\n"); + + $oPage->add("
      \n"); + foreach(MetaModel::GetClasses($sCategory) as $sClassName) + { + if (MetaModel::IsStandaloneClass($sClassName)) + { + $oPage->add("
    • ".MakeClassHLink($sClassName)."
    • \n"); + } + else if (MetaModel::IsRootClass($sClassName)) + { + $oPage->add("
    • ".MakeClassHLink($sClassName)."\n"); + DisplaySubclasses($oPage, $sClassName); + $oPage->add("
    • \n"); + } + } + $oPage->add("
    \n"); + + $oPage->add("\n"); + } + $oPage->add("
\n"); + + + $oPage->add("

Relationships

\n"); + + $oPage->add("
    \n"); + foreach (MetaModel::EnumRelations() as $sRelCode) + { + $oPage->add("
  • ".MakeRelationHLink($sRelCode)."\n"); + $oPage->add("
      \n"); + foreach (MetaModel::EnumRelationProperties($sRelCode) as $sProp => $sValue) + { + $oPage->add("
    • $sProp: ".htmlentities($sValue)."
    • \n"); + } + $oPage->add("
    \n"); + $oPage->add("
  • \n"); + } + $oPage->add("
\n"); + $oPage->add_ready_script('$("#ClassesList").treeview();'); + $oPage->add_ready_script('$("#ClassesRelationships").treeview();'); +} + +/** + * Display the details of a given class of objects + */ +function DisplayClassDetails($oPage, $sClass) +{ + $oPage->p("

$sClass


\n".MetaModel::GetClassDescription($sClass)."
\n"); + $oPage->p("

Class Hierarchy

"); + $oPage->p("[All classes]"); + // List the parent classes + $sParent = MetaModel::GetParentPersistentClass($sClass); + $aParents = array(); + $aParents[] = $sClass; + while($sParent != "" && $sParent != 'cmdbAbstractObject') + { + $aParents[] = $sParent; + $sParent = MetaModel::GetParentPersistentClass($sParent); + } + $iIndex = count($aParents); + $sSpace =""; + $oPage->add("
    "); + while ($iIndex > 0) + { + $iIndex--; + $oPage->add("
  • ".MakeClassHLink($aParents[$iIndex])."\n"); + $oPage->add("
      \n"); + } + for($iIndex = 0; $iIndex < count($aParents); $iIndex++) + { + $oPage->add("
    \n
  • \n"); + } + $oPage->add("
\n"); + $oPage->add_ready_script('$("#ClassHierarchy").treeview();'); + $oPage->p(''); + $oPage->AddTabContainer('details'); + $oPage->SetCurrentTabContainer('details'); + // List the attributes of the object + $aDetails = array(); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef) + { + if ($oAttDef->IsExternalKey()) + { + $sValue = "External key to ".MakeClassHLink($oAttDef->GetTargetClass()); + } + else + { + $sValue = $oAttDef->GetDescription(); + } + $sType = $oAttDef->GetType().' ('.$oAttDef->GetTypeDesc().')'; + $sOrigin = MetaModel::GetAttributeOrigin($sClass, $sAttCode); + $sAllowedValues = ""; + $oAllowedValuesDef = $oAttDef->GetValuesDef(); + $sMoreInfo = ""; + if (is_subclass_of($oAttDef, 'AttributeDBFieldVoid')) + { + $aMoreInfo = array(); + $aMoreInfo[] = "Column: ".$oAttDef->GetSQLExpr().""; + $aMoreInfo[] = "Default: '".$oAttDef->GetDefaultValue()."'"; + $aMoreInfo[] = $oAttDef->IsNullAllowed() ? "Null allowed" : "Null NOT allowed"; + //$aMoreInfo[] = $oAttDef->DBGetUsedFields(); + $sMoreInfo .= implode(', ', $aMoreInfo); + } + + if (is_object($oAllowedValuesDef)) $sAllowedValues = $oAllowedValuesDef->GetValuesDescription(); + else $sAllowedValues = ''; + + $aDetails[] = array('code' => $oAttDef->GetCode(), 'type' => $sType, 'origin' => $sOrigin, 'label' => $oAttDef->GetLabel(), 'description' => $sValue, 'values' => $sAllowedValues, 'moreinfo' => $sMoreInfo); + } + $oPage->SetCurrentTab('Attributes'); + $aConfig = array( 'code' => array('label' => 'Attribute code', 'description' => 'Code of this attribute'), + 'label' => array('label' => 'Label', 'description' => 'Label of this attribute'), + 'type' => array('label' => 'Type', 'description' => 'Data type of this attribute'), + 'origin' => array('label' => 'Origin', 'description' => 'The base class for this attribute'), + 'description' => array('label' => 'Description', 'description' => 'Description of this attribute'), + 'values' => array('label' => 'Allowed Values', 'description' => 'Restrictions on the possible values for this attribute'), + 'moreinfo' => array('label' => 'More info', 'description' => 'More info for the fields related to a Database field'), + ); + $oPage->table($aConfig, $aDetails); + + // List the search criteria for this object + $aDetails = array(); + foreach (MetaModel::GetClassFilterDefs($sClass) as $sFilterCode => $oFilterDef) + { + $aOpDescs = array(); + foreach ($oFilterDef->GetOperators() as $sOpCode => $sOpDescription) + { + $sIsTheLooser = ($sOpCode == $oFilterDef->GetLooseOperator()) ? " (loose search)" : ""; + $aOpDescs[] = "$sOpCode ($sOpDescription)$sIsTheLooser"; + } + $aDetails[] = array( 'code' => $sFilterCode, 'description' => $oFilterDef->GetLabel(),'operators' => implode(" / ", $aOpDescs)); + } + $oPage->SetCurrentTab('Search criteria'); + $aConfig = array( 'code' => array('label' => 'Filter code', 'description' => 'Code of this search criteria'), + 'description' => array('label' => 'Description', 'description' => 'Description of this search criteria'), + 'operators' => array('label' => 'Available operators', 'description' => 'Possible operators for this search criteria') + ); + $oPage->table($aConfig, $aDetails); + + $oPage->SetCurrentTab('Child classes'); + DisplaySubclasses($oPage, $sClass); + + $oPage->SetCurrentTab('Referencing classes'); + DisplayReferencingClasses($oPage, $sClass); + + $oPage->SetCurrentTab('Related classes'); + DisplayRelatedClasses($oPage, $sClass); + + $oPage->SetCurrentTab('Lifecycle'); + DisplayLifecycle($oPage, $sClass); + + $oPage->SetCurrentTab(); + $oPage->SetCurrentTabContainer(); +} + + +/** + * Display the details of a given relation (e.g. "impacts") + */ +function DisplayRelationDetails($oPage, $sRelCode) +{ + $sDesc = MetaModel::GetRelationProperty($sRelCode, 'description'); + $sVerbDown = MetaModel::GetRelationProperty($sRelCode, 'verb_down'); + $sVerbUp = MetaModel::GetRelationProperty($sRelCode, 'verb_up'); + $oPage->add("

Relation $sRelCode ($sDesc)

"); + $oPage->p("Down: $sVerbDown"); + $oPage->p("Up: $sVerbUp"); + + $oPage->add("
    \n"); + foreach(MetaModel::GetClasses() as $sClass) + { + $aRelQueries = MetaModel::EnumRelationQueries($sClass, $sRelCode); + if (count($aRelQueries) > 0) + { + $oPage->add("
  • class ".MakeClassHLink($sClass)."\n"); + $oPage->add("
      \n"); + foreach ($aRelQueries as $sRelKey => $aQuery) + { + $sQuery = $aQuery['sQuery']; + $bPropagate = $aQuery['bPropagate'] ? "Propagate" : "Do not propagate"; + $iDistance = $aQuery['iDistance']; + + $oPage->add("
    • $sRelKey: $bPropagate ($iDistance) ".DBObjectSearch::SibuSQLAsHtml($sQuery)."
    • \n"); + } + $oPage->add("
    \n"); + $oPage->add("
  • \n"); + } + } + $oPage->add_ready_script('$("#RelationshipDetails").treeview();'); +} + + +require_once('../application/loginwebpage.class.inc.php'); +login_web_page::DoLogin(); // Check user rights and prompt if needed + +// Display the menu on the left +$oContext = new UserContext(); +$oAppContext = new ApplicationContext(); +$iActiveNodeId = utils::ReadParam('menu', -1); +$currentOrganization = utils::ReadParam('org_id', 1); +$operation = utils::ReadParam('operation', ''); + +$oPage = new iTopWebPage("iTop objects schema", $currentOrganization); +$oPage->no_cache(); + +$operation = utils::ReadParam('operation', ''); + +switch($operation) +{ + case 'details_class': + $sClass = utils::ReadParam('class', 'logRealObject'); + DisplayClassDetails($oPage, $sClass); + break; + + case 'details_relation': + $sRelCode = utils::ReadParam('relcode', ''); + DisplayRelationDetails($oPage, $sRelCode); + break; + + case 'details': + $oPage->p('operation=details has been deprecated, please use details_class'); + break; + case 'list': + default: + DisplayClassesList($oPage); +} + +$oPage->output(); +?> diff --git a/pages/sibusql.php b/pages/sibusql.php new file mode 100644 index 000000000..cf22cefb1 --- /dev/null +++ b/pages/sibusql.php @@ -0,0 +1,57 @@ +FYI: '$sClearText'
    \n"; + $oFilter = DBObjectSearch::unserialize($sExpression); + $sExpression = $oFilter->ToSibusQL(); + exit; +} +else +{ + // leave $sExpression as is +} + +$oP->add('
    '."\n"); +$oP->add('Expression to evaluate:
    '."\n"); +$oP->add(''."

    Example:
    bizPerson: name Contains 'A'

    \n"); +$oP->add(''."\n"); +$oP->add('
    '."\n"); + +if (!empty($sExpression)) +{ + $oFilter = DBObjectSearch::FromSibusQL($sExpression); + if ($oFilter) + { + $oP->p('Query expression: '.$oFilter->ToSibusQL()); + $oP->p('Serialized filter: '.$oFilter->serialize()); + + $oSet = new CMDBObjectSet($oFilter); + $oP->p('The query returned '.$oSet->count().' results(s)'); + cmdbAbstractObject::DisplaySet($oP, $oSet); + } +} + +$oP->output(); +?> diff --git a/pages/test.php b/pages/test.php new file mode 100644 index 000000000..e9e9bbea4 --- /dev/null +++ b/pages/test.php @@ -0,0 +1,126 @@ +Missing mandatory argument $sName

    "; + exit; + } + return $value; +} + +function IsAValidTestClass($sClassName) +{ + // Must be a child of TestHandler + // + if (!is_subclass_of($sClassName, 'TestHandler')) return false; + + // Must not be abstract + // + $oReflectionClass = new ReflectionClass($sClassName); + if (!$oReflectionClass->isInstantiable()) return false; + + return true; +} + +function DisplayEvents($aEvents, $sTitle) +{ + echo "

    $sTitle

    \n"; + if (count($aEvents) > 0) + { + echo "
      \n"; + foreach ($aEvents as $sEvent) + { + echo "
    • $sEvent
    • \n"; + } + echo "
    \n"; + } + else + { + echo "

    none

    \n"; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Main +/////////////////////////////////////////////////////////////////////////////// + + +require_once('../application/utils.inc.php'); +require_once('../core/test.class.inc.php'); +require_once('testlist.inc.php'); + +require_once('../core/cmdbobject.class.inc.php'); + +$sTodo = utils::ReadParam("todo", ""); +if ($sTodo == '') +{ + // Show the list of tests + // + echo "

    Existing tests

    \n"; + echo "
      \n"; + foreach (get_declared_classes() as $sClassName) + { + if (!IsAValidTestClass($sClassName)) continue; + + $sName = call_user_func(array($sClassName, 'GetName')); + $sDescription = call_user_func(array($sClassName, 'GetDescription')); + echo "
    • $sName ($sDescription)\n"; +} +else if ($sTodo == 'exec') +{ + // Execute a test + // + $sTestClass = ReadMandatoryParam("testid"); + + if (!IsAValidTestClass($sTestClass)) + { + echo "

      Wrong value for testid, expecting a valid class name

      \n"; + } + else + { + $oTest = new $sTestClass(); + echo "

      Testing: ".$oTest->GetName()."

      \n"; + $bRes = $oTest->Execute(); + } + +/* +MyHelpers::var_dump_html($oTest->GetResults()); +MyHelpers::var_dump_html($oTest->GetWarnings()); +MyHelpers::var_dump_html($oTest->GetErrors()); +*/ + + if ($bRes) + { + echo "

      Success :-)

      \n"; + DisplayEvents($oTest->GetResults(), 'Results'); + } + else + { + echo "

      Failure :-(

      \n"; + } + DisplayEvents($oTest->GetErrors(), 'Errors'); + DisplayEvents($oTest->GetWarnings(), 'Warnings'); + + // Render the output + // + echo "

      Actual output

      \n"; + echo "
      \n"; + echo $oTest->GetOutput(); + echo "
      \n"; +} +else +{ +} + + +?> diff --git a/pages/testlist.inc.php b/pages/testlist.inc.php new file mode 100644 index 000000000..571c5a566 --- /dev/null +++ b/pages/testlist.inc.php @@ -0,0 +1,842 @@ +new FieldExpression('column1', 'myTableAlias'), 'column2'=>new FieldExpression('column2', 'myTableAlias')), + $oCondition = new BinaryExpression(new FieldExpression('column1', 'myTableAlias'), 'LIKE', new ScalarExpression('trash')), + $aFullTextNeedles = array('column1'), + $bToDelete = false, + $aValues = array() + ); + $oQuery->AddCondition(Expression::FromOQL('DATE(NOW() - 1200 * 2) > \'2008-07-31\'')); + + $oSubQuery1 = new SQLQuery( + $sTable = 'myTable1', + $sTableAlias = 'myTable1Alias', + $aFields = array('column1_1'=>new FieldExpression('column1', 'myTableAlias'), 'column1_2'=>new FieldExpression('column1', 'myTableAlias')), + $oCondition = new TrueSQLExpression, + $aFullTextNeedles = array(), + $bToDelete = false, + $aValues = array() + ); + + $oSubQuery2 = new SQLQuery( + $sTable = 'myTable2', + $sTableAlias = 'myTable2Alias', + $aFields = array('column2_1'=>new FieldExpression('column2', 'myTableAlias'), 'column2_2'=>new FieldExpression('column2', 'myTableAlias')), + $oCondition = new TrueSQLExpression, + $aFullTextNeedles = array(), + $bToDelete = false, + $aValues = array() + ); + + $oQuery->AddInnerJoin($oSubQuery1, 'column1', 'column1_1'); + $oQuery->AddLeftJoin($oSubQuery2, 'column2', 'column2_2'); + + $oQuery->DisplayHtml(); + $oQuery->RenderDelete(); + $oQuery->RenderUpdate(); + echo '

      '.$oQuery->RenderSelect().'

      '; + $oQuery->RenderSelect(array('column1')); + $oQuery->RenderSelect(array('column1', 'column2')); + } +} + +class TestOQLParser extends TestFunction +{ + static public function GetName() {return 'Check OQL parsing';} + static public function GetDescription() {return 'Attempts a series of queries, and in particular those with a bad syntax';} + + protected function CheckQuery($sQuery, $bIsCorrectQuery) + { + $oOql = new OqlInterpreter($sQuery); + try + { + $oTrash = $oOql->ParseQuery(); + MyHelpers::var_dump_html($oTrash, true); + } + catch (OQLException $OqlException) + { + if ($bIsCorrectQuery) + { + echo "

      More info on this unexpected failure:
      ".$OqlException->getHtmlDesc()."

      \n"; + throw $OqlException; + return false; + } + else + { + // Everything is fine :-) + echo "

      More info on this expected failure:
      ".$OqlException->getHtmlDesc()."

      \n"; + return true; + } + } + // The query was correctly parsed, was it expected to be correct ? + if ($bIsCorrectQuery) + { + return true; + } + else + { + throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)"); + return false; + } + } + + protected function TestQuery($sQuery, $bIsCorrectQuery) + { + if (!$this->CheckQuery($sQuery, $bIsCorrectQuery)) + { + return false; + } + return true; + } + + public function DoExecute() + { + $aQueries = array( + 'SELECT toto' => true, + 'SELECT toto WHERE toto.a = 1' => true, + 'SELECT toto WHERE toto.a=1' => true, + 'SELECT toto WHERE toto.a = "1"' => true, + 'SELECT toto WHHHERE toto.a = "1"' => false, + 'SELECT toto WHERE toto.a == "1"' => false, + 'SELECT toto WHERE toto.a % 1' => false, + //'SELECT toto WHERE toto.a LIKE 1' => false, + 'SELECT toto WHERE toto.a like \'arg\'' => false, + 'SELECT toto WHERE toto.a NOT LIKE "That\'s it"' => true, + 'SELECT toto WHERE toto.a NOT LIKE "That\'s "it""' => false, + 'SELECT toto WHERE toto.a NOT LIKE "That\'s \\"it\\""' => true, + 'SELECT toto WHERE toto.a NOT LIKE \'That"s it\'' => true, + 'SELECT toto WHERE toto.a NOT LIKE \'That\'s it\'' => false, + 'SELECT toto WHERE toto.a NOT LIKE \'That\\\'s it\'' => true, + 'SELECT toto WHERE toto.a NOT LIKE "blah \\ truc"' => false, + 'SELECT toto WHERE toto.a NOT LIKE "blah \\\\ truc"' => true, + 'SELECT toto WHERE toto.a NOT LIKE \'blah \\ truc\'' => false, + 'SELECT toto WHERE toto.a NOT LIKE \'blah \\\\ truc\'' => true, + + 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true, + 'SELECT toto WHERE toto.a NOT LIKE "\\""' => true, + 'SELECT toto WHERE toto.a NOT LIKE "\\"\\\\"' => true, + 'SELECT toto WHERE toto.a NOT LIKE "\\\\\\""' => true, + 'SELECT toto WHERE toto.a NOT LIKE ""' => true, + 'SELECT toto WHERE toto.a NOT LIKE "\\\\"' => true, + "SELECT UserRightsMatrixClassGrant WHERE UserRightsMatrixClassGrant.class = 'lnkContactRealObject' AND UserRightsMatrixClassGrant.action = 'modify' AND UserRightsMatrixClassGrant.login = 'Denis'" => true, + "SELECT A WHERE A.col1 = 'lit1' AND A.col2 = 'lit2' AND A.col3 = 'lit3'" => true, + + 'SELECT toto WHERE toto.a NOT LIKE "blah" AND toto.b LIKE "foo"' => true, + + //'SELECT toto WHERE toto.a > \'asd\'' => false, + 'SELECT toto WHERE toto.a = 1 AND toto.b LIKE "x" AND toto.f >= 12345' => true, + 'SELECT Device JOIN Site ON Device.site = Site.id' => true, + 'SELECT Device JOIN Site ON Device.site = Site.id JOIN Country ON Site.location = Country.id' => true, + + "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = 123 AND B.col1 = 'aa') OR (A.col3 = 'zzz' AND B.col4 > 100)" => true, + "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 = B.col2 AND B.col1 = A.col2) OR (A.col3 = '' AND B.col4 > 100)" => true, + "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + B.col2 * B.col1 = A.col2" => true, + "SELECT A JOIN B ON A.myB = B.id WHERE A.col1 + (B.col2 * B.col1) = A.col2" => true, + "SELECT A JOIN B ON A.myB = B.id WHERE (A.col1 + B.col2) * B.col1 = A.col2" => true, + + 'SELECT Device AS D_ JOIN Site AS S_ ON D_.site = S_.id WHERE S_.country = "Francia"' => true, + ); + + $iErrors = 0; + + foreach($aQueries as $sQuery => $bIsCorrectQuery) + { + $sIsOk = $bIsCorrectQuery ? 'good' : 'bad'; + echo "

      Testing query: $sQuery ($sIsOk)

      \n"; + $bRet = $this->TestQuery($sQuery, $bIsCorrectQuery); + if (!$bRet) $iErrors++; + } + + return ($iErrors == 0); + } +} + + +class TestGenericItoMyModel extends TestBizModelGeneric +{ + static public function GetName() + { + return 'Generic RO test on '.self::GetConfigFile(); + } + + static public function GetConfigFile() {return '../config-test-mymodel.php';} +} + +class TestGenericItopBigModel extends TestBizModelGeneric +{ + static public function GetName() + { + return 'Generic RO test on '.self::GetConfigFile(); + } + + static public function GetConfigFile() {return '../config-test-itopv06.php';} +} + +class TestUserRightsMatrixItop extends TestUserRights +{ + static public function GetName() + { + return 'User rights test on user rights matrix'; + } + + static public function GetDescription() + { + return 'blah blah blah'; + } + + public function DoPrepare() + { + parent::DoPrepare(); + MetaModel::Startup('../config-test-itopv06.php'); + } + + protected function DoExecute() + { + $sUser = 'Romain'; + echo "

      Totor: ".(UserRights::Login('Totor', 'toto') ? 'ok' : 'NO')."

      \n"; + echo "

      Romain: ".(UserRights::Login('Romain', 'toto') ? 'ok' : 'NO')."

      \n"; + echo "

      User: ".UserRights::GetUser()."

      \n"; + echo "

      On behalf of...".UserRights::GetRealUser()."

      \n"; + + echo "

      Denis (impersonate) : ".(UserRights::Impersonate('Denis', 'tutu') ? 'ok' : 'NO')."

      \n"; + echo "

      User: ".UserRights::GetUser()."

      \n"; + echo "

      On behalf of...".UserRights::GetRealUser()."

      \n"; + + UserRights::GetFilter('bizOrganization'); // returns a filter object + + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT bizOrganization")); + echo "

      IsActionAllowed...".(UserRights::IsActionAllowed('bizOrganization', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."

      \n"; + echo "

      IsStimulusAllowed...".(UserRights::IsStimulusAllowed('bizOrganization', 'myStimulus', $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."

      \n"; + echo "

      IsActionAllowedOnAttribute...".(UserRights::IsActionAllowedOnAttribute('bizOrganization', 'myattribute', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO')."

      \n"; + return true; + } +} + +/////////////////////////////////////////////////////////////////////////// +// Test a complex biz model on the fly +/////////////////////////////////////////////////////////////////////////// + +class TestMyBizModel extends TestBizModel +{ + static public function GetName() + { + return 'A series of tests on a weird business model'; + } + + static public function GetDescription() + { + return 'Attempts various operations and build complex queries'; + } + + static public function GetConfigFile() {return '../config-test-mymodel.php';} + + function test_linksinfo() + { + echo "

      Enum links

      "; + MyHelpers::var_dump_html(MetaModel::EnumReferencedClasses("cmdbTeam")); + MyHelpers::var_dump_html(MetaModel::EnumReferencingClasses("Organization")); + + MyHelpers::var_dump_html(MetaModel::EnumLinkingClasses()); + MyHelpers::var_dump_html(MetaModel::EnumLinkingClasses("cmdbContact")); + MyHelpers::var_dump_html(MetaModel::EnumLinkingClasses("cmdWorkshop")); + MyHelpers::var_dump_html(MetaModel::GetLinkLabel("Liens_entre_contacts_et_workshop", "toworkshop")); + } + + function test_list_attributes() + { + echo "

      List attributes

      "; + foreach(MetaModel::ListAttributeDefs("cmdbTeam") as $sAttCode=>$oAttDef) + { + echo $oAttDef->GetLabel()." / ".$oAttDef->GetDescription()." / ".$oAttDef->GetType()."
      \n"; + } + } + + function test_search() + { + echo "

      Two searches

      "; + $oFilterAllDevs = new DBObjectSearch("cmdbTeam"); + $oAllDevs = new DBObjectSet($oFilterAllDevs); + + echo "Found ".$oAllDevs->Count()." items.
      \n"; + while ($oDev = $oAllDevs->Fetch()) + { + $aValues = array(); + foreach(MetaModel::GetAttributesList($oAllDevs->GetClass()) as $sAttCode) + { + $aValues[] = MetaModel::GetLabel(get_class($oDev), $sAttCode)." (".MetaModel::GetDescription(get_class($oDev), $sAttCode).") = ".$oDev->GetAsHTML($sAttCode); + } + echo $oDev->GetKey()." => ".implode(", ", $aValues)."
      \n"; + } + + // a second one + $oMyFilter = new DBObjectSearch("cmdbContact"); + //$oMyFilter->AddCondition("name", "aii", "Finishes with"); + $oMyFilter->AddCondition("name", "aii"); + $this->search_and_show_list($oMyFilter); + + } + + function test_reload() + { + echo "

      Reload

      "; + $team = MetaModel::GetObject("cmdbContact", "2"); + echo "Chargement de l'attribut headcount: {$team->Get("headcount")}
      \n"; + MyHelpers::var_dump_html($team); + } + + function test_setattribute() + { + echo "

      Set attribute and update

      "; + $team = MetaModel::GetObject("cmdbTeam", "2"); + $team->Set("headcount", rand(1,1000)); + $team->Set("email", "Luis ".rand(9,250)); + MyHelpers::var_dump_html($team->ListChanges()); + echo "New headcount = {$team->Get("headcount")}
      \n"; + echo "Computed name = {$team->Get("name")}
      \n"; + + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "test_setattribute / Made by robot #".rand(1,100)); + $iChangeId = $oMyChange->DBInsert(); + + //MetaModel::StartDebugQuery(); + $team->DBUpdateTracked($oMyChange); + //MetaModel::StopDebugQuery(); + + echo "

      Check the modified team

      "; + $oTeam = MetaModel::GetObject("cmdbTeam", "2"); + MyHelpers::var_dump_html($oTeam); + } + function test_newobject() + { + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "test_newobject / Made by robot #".rand(1,100)); + $iChangeId = $oMyChange->DBInsert(); + + echo "

      Create a new object (team)

      "; + $oNewTeam = MetaModel::NewObject("cmdbTeam"); + $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000)); + $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com"); + $oNewTeam->Set("email", null); + $oNewTeam->Set("owner", "ITOP"); + $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value + $iId = $oNewTeam->DBInsertTracked($oMyChange); + echo "Created new team: $iId
      "; + echo "

      Delete team #$iId

      "; + $oTeam = MetaModel::GetObject("cmdbTeam", $iId); + $oTeam->DBDeleteTracked($oMyChange); + echo "Deleted team: $iId
      "; + MyHelpers::var_dump_html($oTeam); + } + + + function test_updatecolumn() + { + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "test_updatecolumn / Made by robot #".rand(1,100)); + $iChangeId = $oMyChange->DBInsert(); + + $sNewEmail = "updatecol".rand(9,250)."@quedlaballe.com"; + echo "

      Update a the email: set to '$sNewEmail'

      "; + $oMyFilter = new DBObjectSearch("cmdbContact"); + $oMyFilter->AddCondition("name", "o", "Contains"); + + echo "Candidates before:
      "; + $this->search_and_show_list($oMyFilter); + + MetaModel::BulkUpdateTracked($oMyChange, $oMyFilter, array("email" => $sNewEmail)); + + echo "Candidates after:
      "; + $this->search_and_show_list($oMyFilter); + } + + function test_error() + { + trigger_error("Stop requested", E_USER_ERROR); + } + + function test_changetracking() + { + echo "

      Create a change

      "; + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "Made by robot #".rand(1,100)); + $iChangeId = $oMyChange->DBInsert(); + echo "Created new change: $iChangeId
      "; + MyHelpers::var_dump_html($oMyChange); + + echo "

      Create a new object (team)

      "; + $oNewTeam = MetaModel::NewObject("cmdbTeam"); + $oNewTeam->Set("name", "ekip2choc #".rand(1000, 2000)); + $oNewTeam->Set("email", "machin".rand(1,100)."@tnut.com"); + $oNewTeam->Set("email", null); + $oNewTeam->Set("owner", "ITOP"); + $oNewTeam->Set("headcount", "0".rand(38000, 38999)); // should be reset to an int value + $iId = $oNewTeam->DBInsertTracked($oMyChange); + echo "Created new team: $iId
      "; + echo "

      Delete team #$iId

      "; + $oTeam = MetaModel::GetObject("cmdbTeam", $iId); + $oTeam->DBDeleteTracked($oMyChange); + echo "Deleted team: $iId
      "; + MyHelpers::var_dump_html($oTeam); + } + + function test_zlist() + { + echo "

      Test ZLists

      "; + $aZLists = MetaModel::EnumZLists(); + foreach ($aZLists as $sListCode) + { + $aListInfos = MetaModel::GetZListInfo($sListCode); + echo "

      List '".$sListCode."' (".$aListInfos["description"].") of type '".$aListInfos["type"]."'

      \n"; + + foreach (MetaModel::GetSubclasses("cmdbObjectHomeMade") as $sKlass) + { + $aItems = MetaModel::GetZListItems($sKlass, $sListCode); + if (count($aItems) == 0) continue; + + echo "$sKlass - $sListCode : {".implode(", ", $aItems)."}
      \n"; + } + } + + echo "

      IsAttributeInZList()...

      "; + echo "Liens_entre_contacts_et_workshop::ws_info in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "ws_info") ? "yes" : "no")."
      \n"; + echo "Liens_entre_contacts_et_workshop::toworkshop in list1 ? ".(MetaModel::IsAttributeInZList("Liens_entre_contacts_et_workshop", "list1", "toworkshop") ? "yes" : "no")."
      \n"; + + } + + function test_SibuSQL() + { + echo "

      Simple But Structured Query Language

      "; + + $oMyFilter = new DBObjectSearch("cmdbContact"); + echo "Tous les contacts: ".$oMyFilter->ToSibuSQL()."
      \n"; + $oNewFilter = DBObjectSearch::FromSibuSQL($oMyFilter->ToSibuSQL()); + echo "En passant par un filtre, ca revient en : ".$oNewFilter->ToSibuSQL()."
      \n"; + $this->search_and_show_list($oNewFilter); + + $sFilterDesc = "cmdbContact: name Begins with '$[debutnom:as:debut du nom]' AND ownername NotLike $[ddd::]"; + echo "Construction d'un filtre a partir de sa description en SibuSQL: $sFilterDesc
      \n"; + + MyHelpers::var_dump_html(DBObjectSearch::ListSibusQLParams($sFilterDesc)); + $oNewFilter = DBObjectSearch::FromSibuSQL($sFilterDesc, array('ddd'=>123)); + echo "Ca revient en: ".$oNewFilter->ToSibuSQL(); + } + + function test_pkey() + { + echo "

      Test search on pkey

      "; + $sExpr1 = "cmdbContact: pkey IN {40, 42}"; + $sExpr2 = "cmdbContact: pkey NOTIN {40, 42}"; + $this->search_and_show_list_from_sibusql($sExpr1); + $this->search_and_show_list_from_sibusql($sExpr2); + + echo "Et maintenant, on fusionne....
      \n"; + $oSet1 = new CMDBObjectSet(DBObjectSearch::FromSibuSQL($sExpr1)); + $oSet2 = new CMDBObjectSet(DBObjectSearch::FromSibuSQL($sExpr2)); + $oIntersect = $oSet1->CreateIntersect($oSet2); + $oDelta = $oSet1->CreateDelta($oSet2); + + $oMerge = clone $oSet1; + $oMerge->Merge($oSet2); + $oMerge->Merge($oSet2); + + echo "Set1 - Found ".$oSet1->Count()." items.
      \n"; + echo "Set2 - Found ".$oSet2->Count()." items.
      \n"; + echo "Intersect - Found ".$oIntersect->Count()." items.
      \n"; + echo "Delta - Found ".$oDelta->Count()." items.
      \n"; + echo "Merge - Found ".$oMerge->Count()." items.
      \n"; + //$this->show_list($oObjSet); + } + + function test_relations() + { + echo "

      Test relations

      "; + + //MyHelpers::var_dump_html(MetaModel::EnumRelationQueries("cmdbObjectHomeMade", "Potes")); + MyHelpers::var_dump_html(MetaModel::EnumRelationQueries("cmdbContact", "Potes")); + + $iMaxDepth = 9; + echo "Max depth = $iMaxDepth
      \n"; + + $oObj = MetaModel::GetObject("cmdbContact", 18); + $aRels = $oObj->GetRelatedObjects("Potes", $iMaxDepth); + echo $oObj->Get('name')." has some 'Potes'...
      \n"; + foreach ($aRels as $sClass => $aObjs) + { + echo "$sClass, count = ".count($aObjs)." => ".implode(', ', array_keys($aObjs))."
      \n"; + $oObjectSet = CMDBObjectSet::FromArray($sClass, $aObjs); + $this->show_list($oObjectSet); + } + + echo "

      Test relations - same results, by the mean of a SibuSQL

      "; + $this->search_and_show_list_from_sibusql("cmdbContact: RELATED (Potes, $iMaxDepth) TO (cmdbContact: pkey = 18)"); + + } + + function test_linkedset() + { + echo "

      Linked set attributes

      \n"; + $oObj = MetaModel::GetObject("cmdbContact", 18); + + echo "
      Current workshops
      \n"; + $oSetWorkshopsCurr = $oObj->Get("myworkshops"); + $this->show_list($oSetWorkshopsCurr); + + echo "
      Setting workshops
      \n"; + $oNewLink = new cmdbLiens(); + $oNewLink->Set('toworkshop', 2); + $oNewLink->Set('function', 'mafonctioooon'); + $oNewLink->Set('a1', 'tralala1'); + $oNewLink->Set('a2', 'F7M'); + $oSetWorkshops = CMDBObjectSet::FromArray("cmdbLiens", array($oNewLink)); + $oObj->Set("myworkshops", $oSetWorkshops); + $this->show_list($oSetWorkshops); + + echo "
      New workshops
      \n"; + $oSetWorkshopsCurr = $oObj->Get("myworkshops"); + $this->show_list($oSetWorkshopsCurr); + + $oMyChange = MetaModel::NewObject("CMDBChange"); + $oMyChange->Set("date", time()); + $oMyChange->Set("userinfo", "test_linkedset / Made by robot #".rand(1,100)); + $iChangeId = $oMyChange->DBInsert(); + $oObj->DBUpdateTracked($oMyChange); + $oObj = MetaModel::GetObject("cmdbContact", 18); + + echo "
      After the write
      \n"; + $oSetWorkshopsCurr = $oObj->Get("myworkshops"); + $this->show_list($oSetWorkshopsCurr); + } + + function test_object_lifecycle() + { + echo "

      Test object lifecycle

      "; + + + MyHelpers::var_dump_html(MetaModel::GetStateAttributeCode("cmdbContact")); + MyHelpers::var_dump_html(MetaModel::EnumStates("cmdbContact")); + MyHelpers::var_dump_html(MetaModel::EnumStimuli("cmdbContact")); + foreach(MetaModel::EnumStates("cmdbContact") as $sStateCode => $aStateDef) + { + echo "

      Transition from $sStateCode

      \n"; + MyHelpers::var_dump_html(MetaModel::EnumTransitions("cmdbContact", $sStateCode)); + } + + $oObj = MetaModel::GetObject("cmdbContact", 18); + echo "Current state: ".$oObj->GetState()."... let's go to school..."; + MyHelpers::var_dump_html($oObj->EnumTransitions()); + $oObj->ApplyStimulus("toschool"); + echo "New state: ".$oObj->GetState()."... let's get older..."; + MyHelpers::var_dump_html($oObj->EnumTransitions()); + $oObj->ApplyStimulus("raise"); + echo "New state: ".$oObj->GetState()."... let's try to go further... (should give an error)"; + MyHelpers::var_dump_html($oObj->EnumTransitions()); + $oObj->ApplyStimulus("raise"); // should give an error + } + + + protected function DoExecute() + { +// $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: $sExpr1 != $sExpr2"); +// $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName"); + //$this->test_linksinfo(); + //$this->test_list_attributes(); + //$this->test_search(); + //$this->test_reload(); + //$this->test_newobject(); + $this->test_setattribute(); + //$this->test_updatecolumn(); + //$this->test_error(); + //$this->test_changetracking(); + $this->test_zlist(); + $this->test_SibuSQL(); + //$this->test_pkey(); + $this->test_relations(); + $this->test_linkedset(); + $this->test_object_lifecycle(); + return true; + } +} + + +/////////////////////////////////////////////////////////////////////////// +// Test a complex biz model on the fly +/////////////////////////////////////////////////////////////////////////// + +class TestQueriesOnFarm extends TestBizModel +{ + static public function GetName() + { + return 'Farm test'; + } + + static public function GetDescription() + { + return 'A series of tests on the farm business model (SQL generation)'; + } + + static public function GetConfigFile() {return '../config-test-farm.php';} + + protected function DoPrepare() + { + parent::DoPrepare(); + $this->ResetDB(); + MetaModel::DBCheckIntegrity(); + } + + + private function InsertMammal($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $sName, $iHeight, $sBirth) + { + $oNew = MetaModel::NewObject('Mammal'); + $oNew->Set('species', $sSpecies); + $oNew->Set('sex', $sSex); + $oNew->Set('speed', $iSpeed); + $oNew->Set('mother', $iMotherid); + $oNew->Set('father', $iFatherId); + $oNew->Set('name', $sName); + $oNew->Set('height', $iHeight); + $oNew->Set('birth', $sBirth); + $iId = $oNew->DBInsert(); + return $iId; + } + + private function InsertBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId) + { + $oNew = MetaModel::NewObject('Bird'); + $oNew->Set('species', $sSpecies); + $oNew->Set('sex', $sSex); + $oNew->Set('speed', $iSpeed); + $oNew->Set('mother', $iMotherid); + $oNew->Set('father', $iFatherId); + $iId = $oNew->DBInsert(); + return $iId; + } + + private function InsertFlyingBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $iFlyingSpeed) + { + $oNew = MetaModel::NewObject('FlyingBird'); + $oNew->Set('species', $sSpecies); + $oNew->Set('sex', $sSex); + $oNew->Set('speed', $iSpeed); + $oNew->Set('mother', $iMotherid); + $oNew->Set('father', $iFatherId); + $oNew->Set('flyingspeed', $iFlyingSpeed); + $iId = $oNew->DBInsert(); + return $iId; + } + + private function InsertGroup($sName, $iLeaderId) + { + $oNew = MetaModel::NewObject('Group'); + $oNew->Set('name', $sName); + $oNew->Set('leader', $iLeaderId); + $iId = $oNew->DBInsert(); + return $iId; + } + + protected function CheckQuery($sQuery, $bIsCorrectQuery) + { + if ($bIsCorrectQuery) + { + echo "

      $sQuery

      \n"; + } + else + { + echo "

      $sQuery

      \n"; + } + try + { + //$oOql = new OqlInterpreter($sQuery); + //$oTrash = $oOql->ParseQuery(); + //MyHelpers::var_dump_html($oTrash, true); + $oMyFilter = DBObjectSearch::FromOQL($sQuery); + } + catch (OQLException $oOqlException) + { + if ($bIsCorrectQuery) + { + echo "

      More info on this unexpected failure:
      ".$oOqlException->getHtmlDesc()."

      \n"; + throw $oOqlException; + return false; + } + else + { + // Everything is fine :-) + echo "

      More info on this expected failure:\n"; + echo "

        \n"; + echo "
      • ".get_class($oOqlException)."
      • \n"; + echo "
      • ".$oOqlException->getMessage()."
      • \n"; + echo "
      • ".$oOqlException->getHtmlDesc()."
      • \n"; + echo "
      \n"; + echo "

      \n"; + return true; + } + } + // The query was correctly parsed, was it expected to be correct ? + if (!$bIsCorrectQuery) + { + throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)"); + return false; + } + + $this->search_and_show_list($oMyFilter); + + //echo "

      first pass

      \n"; + //MyHelpers::var_dump_html($oMyFilter, true); + $sQuery1 = MetaModel::MakeSelectQuery($oMyFilter); + //echo "

      second pass

      \n"; + //MyHelpers::var_dump_html($oMyFilter, true); + //$sQuery1 = MetaModel::MakeSelectQuery($oMyFilter); + + $sSerialize = $oMyFilter->serialize(); + echo "

      Serialized:$sSerialize

      \n"; + $oFilter2 = DBObjectSearch::unserialize($sSerialize); + try + { + $sQuery2 = MetaModel::MakeSelectQuery($oFilter2); + } + catch (Exception $e) + { + echo "

      Could not compute the query after unserialize

      \n"; + echo "

      Query 1: $sQuery1

      \n"; + MyHelpers::var_dump_html($oMyFilter, true); + echo "

      Query 2: FAILED

      \n"; + MyHelpers::var_dump_html($oFilter2, true); + throw $e; + } + //if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same! + if ($sQuery1 != $sQuery2) + { + echo "

      serialize/unserialize mismatch :-(

      \n"; + echo "

      Query 1: $sQuery1

      \n"; + MyHelpers::var_dump_html($oMyFilter, true); + echo "

      Query 2: $sQuery2

      \n"; + MyHelpers::var_dump_html($oFilter2, true); + return false; + } + return true; + } + + protected function DoExecute() + { +// $this->ReportError("Found two different SibuSQL expression out of the (same?) filter: $sExpr1 != $sExpr2"); +// $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName"); + echo "

      Create protagonists...

      "; + + $iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19'); + $iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23'); + $this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23'); + $this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01'); + $this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11'); + + $this->InsertBird('rooster', 'male', 12, 0, 0); + $this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35); + + // Benchmarking + // + if (false) + { + define ('COUNT_BENCHMARK', 10); + echo "

      Parsing a long query, ".COUNT_BENCHMARK." times

      "; + $sQuery = "SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR) AND Dad.height * 2 <= ROUND(TO_DAYS(Dad.birth) / (3 + 1) * 5 - 3)"; + + $fStart = MyHelpers::getmicrotime(); + for($i=0 ; $i < COUNT_BENCHMARK ; $i++) + { + $oMyFilter = DBObjectSearch::FromOQL($sQuery); + } + $fDuration = MyHelpers::getmicrotime() - $fStart; + $fParsingDuration = $fDuration / COUNT_BENCHMARK; + echo "

      Mean time by op: $fParsingDuration

      "; + } + + echo "

      Test queries...

      "; + + $aQueries = array( + 'SELECT Animal' => true, + 'SELECT Aniiimal' => false, + 'SELECTe Animal' => false, + 'SELECT * FROM Animal' => false, + 'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true, + 'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true, + 'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false, + 'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true, + 'SELECT Animal AS zoo WHERE zoo.species NOT IN (\'human\', "pig")' => true, + 'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false, + 'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true, + 'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true, + 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true, + 'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true, + 'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true, + 'SELECT Mammal AS m WHERE m.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR)' => true, + 'SELECT Mammal AS m WHERE m.birth > DATE_SUB(NOW(), INTERVAL 2000 DAY)' => true, + 'SELECT Mammal AS m WHERE (TO_DAYS(NOW()) - TO_DAYS(m.birth)) > 2000' => true, + 'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true, + 'SELECT Mammal AS m WHERE (1 + 2' => false, + 'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true, + 'SELECT Mammal AS m WHERE 1/0' => true, + 'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true, + 'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true, + 'SELECT Animal AS A JOIN Group AS G1 ON G1.leader = A.id' => true, + 'SELECT Animal AS A JOIN Group AS G ON FooClass.leader = A.id' => false, + 'SELECT Animal AS A JOIN Group AS G ON G.leader = FooClass.id' => false, + 'SELECT Animal AS A JOIN Group AS G ON G.masterchief = A.id' => false, + 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.pkey' => false, + 'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false, + 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false, + 'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true, + 'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false, + 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true, + 'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false, + 'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true, + 'SELECT Group AS G WHERE G.leader_speed < 100000' => true, + 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true, + 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true, + 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true, + 'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true, + 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true, + 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.pkey = 1' => true, + 'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => false, + 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true, + 'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => true, + ); + //$aQueries = array( + // 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true, + //); + foreach($aQueries as $sQuery => $bIsCorrect) + { + $this->CheckQuery($sQuery, $bIsCorrect); + } + return true; + } +} + +?>