├── .gitignore ├── .styleci.yml ├── LICENSE ├── README.md ├── composer.json └── src └── CallmanagerAXL └── Callmanager.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: recommended 2 | 3 | linting: true 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | 167 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP7-CallManager-AXL 2 | PHP Implementation to interface with Cisco unified call manager (CUCM) over the administrative XML (AXL) implememtation. 3 | This library requires a copy of the CORRECT .WSDL file for YOUR VERSION of callmanager. 4 | This library is under development so should be considered unstable and subject to major changes. 5 | 6 | ## Naming Convention 7 | 8 | ``` 9 | This library is dependent on a naming convention specific to the owner's environment. Use at your own risk. 10 | 11 | ``` 12 | 13 | |Object Type|Example Name| 14 | |------------------|--------------------| 15 | |Route Group|RG_{$SITE} | 16 | |Media Resourse Group List|MRGL_{$SITE} | 17 | |Media Resourse Group|MRG_{$SITE} | 18 | |Media Terminiation Point|{$SITE}_711 | 19 | |Media Terminiation Point|{$SITE}_729 | 20 | |Conference Bridge|{$SITE}_CFB | 21 | |Device Pool|DP_{$SITE} | 22 | |Call Manager Group|CMG-{$SITE} | 23 | |Region|R_{$SITE} | 24 | |Location|LOC_{$SITE} | 25 | |Calling Search Space|CSS_{$SITE} | 26 | |Partition|PT_{$SITE} | 27 | |SRST |SRST_{$SITE} | 28 | 29 | 30 | ## Install via Composer 31 | 32 | ``` 33 | composer require iahunter/php5-callmanager-axl 34 | ``` 35 | ### Example - List Device Pool Names 36 | 37 | ```php 38 | require_once "./vendor/autoload.php"; 39 | 40 | $URL = "https://10.11.12.13:8443/axl"; // Prod CUCM 41 | $SCHEMA = "./axl/schema/10.5/AXLAPI.wsdl"; 42 | $USER = "username"; 43 | $PASS = "password"; 44 | 45 | try { 46 | $CUCM = new \Iahunter\CallmanagerAXL\Callmanager($URL, $SCHEMA, $USER, $PASS); 47 | 48 | $DP = $CUCM->get_device_pool_names(); 49 | print_r($DP); 50 | 51 | } catch (\Exception $E) { 52 | echo "Error communicating with callmanager: {$E->getMessage()}".PHP_EOL; 53 | } 54 | ``` 55 | 56 | ### Example - List Phone Names 57 | 58 | ```php 59 | require_once "./vendor/autoload.php"; 60 | 61 | $URL = "https://10.11.12.13:8443/axl"; // Prod CUCM 62 | $SCHEMA = "./axl/schema/10.5/AXLAPI.wsdl"; 63 | $USER = "username"; 64 | $PASS = "password"; 65 | 66 | try { 67 | $CUCM = new \Iahunter\CallmanagerAXL\Callmanager($URL, $SCHEMA, $USER, $PASS); 68 | 69 | $PHONES = $CUCM->get_phone_names(); 70 | print_r($PHONES); 71 | 72 | } catch (\Exception $E) { 73 | echo "Error communicating with callmanager: {$E->getMessage()}".PHP_EOL; 74 | } 75 | ``` 76 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iahunter/php5-callmanager-axl", 3 | "type": "library", 4 | "description": "PHP Cisco CallManager AXL SOAP/XML Library", 5 | "keywords": [ 6 | "php5", 7 | "php7", 8 | "cisco", 9 | "callmanager", 10 | "call", 11 | "manager", 12 | "axl", 13 | "voip" 14 | ], 15 | "homepage": "http://github.com/iahunter/php5-callmanager-axl", 16 | "license": "LGPL3.0", 17 | "authors": [ 18 | { 19 | "name": "John.Lavoie", 20 | "email": "composer@secureobscure.com", 21 | "role": "Developer" 22 | }, 23 | { 24 | "name": "Travis Riesenberg", 25 | "email": "Travis.Riesenberg@kiewit.com", 26 | "role": "Developer" 27 | } 28 | ], 29 | "minimum-stability": "dev", 30 | "require-dev": { 31 | "phpunit/phpunit": "~4.0" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Iahunter\\": "src" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CallmanagerAXL/Callmanager.php: -------------------------------------------------------------------------------- 1 | true, 48 | 'exceptions' => true, 49 | 'stream_context' => stream_context_create( 50 | ['ssl' => [ 51 | 'verify_peer' => false, 52 | 'verify_peer_name' => false, 53 | 'allow_self_signed' => true, 54 | ], 55 | ]), 56 | 'connection_timeout' => 10, 57 | 'location' => $URL, 58 | 'login' => $USERNAME, 59 | 'password' => $PASSWORD, 60 | ]; 61 | $this->SOAPCLIENT = new \SoapClient($SCHEMA, $OPTIONS); 62 | $this->SOAPCALLS = []; 63 | } 64 | 65 | // Keep track of our soap calls for performance and debugging 66 | 67 | private function log_soap_call($CALL, $TIME, $QUERY, $REPLY) 68 | { 69 | array_push($this->SOAPCALLS, 70 | [ 71 | 'call' => $CALL, 72 | 'time' => $TIME, 73 | 'query' => $QUERY, 74 | 'reply' => $REPLY, 75 | ] 76 | ); 77 | 78 | return count($this->SOAPCALLS); 79 | } 80 | 81 | public function microtimeTicks() 82 | { 83 | // Turn microtime into an array (12345 0.7563262) 84 | $ticks = explode(' ', microtime()); 85 | // Return the sum of the two numbers (double precision number) 86 | return $ticks[0] + $ticks[1]; 87 | } 88 | 89 | // This converts an object returned by a soap reply from StdClass to associative array 90 | 91 | public function object_to_assoc($OBJECT) 92 | { 93 | return json_decode(json_encode($OBJECT), true); 94 | } 95 | 96 | // This decodes soap reply objects and ensures the format is correct 97 | // Every response will be an array of the responses, even if its just one response 98 | 99 | public function decode_soap_reply($SOAPREPLY) 100 | { 101 | if (!is_object($SOAPREPLY)) { 102 | throw new \Exception('SOAP reply is not an object'); 103 | } 104 | if (!property_exists($SOAPREPLY, 'return')) { 105 | throw new \Exception('SOAP reply does not have the property return'); 106 | } 107 | $SOAPRETURN = $SOAPREPLY->return; 108 | $SOAPOBJVARS = get_object_vars($SOAPRETURN); 109 | $RETURN = reset($SOAPOBJVARS); 110 | if (is_object($RETURN)) { 111 | // Single objects mean we recieved exactly one element in the reply 112 | $RETURN = [$this->object_to_assoc($RETURN)]; 113 | } else { 114 | // Otherwise we recieved multiple elements in the reply. 115 | $RETURN = $this->object_to_assoc($RETURN); 116 | } 117 | 118 | return $RETURN; 119 | } 120 | 121 | // This converts an array of key=>value pairs into a flat array of one of the keys values 122 | 123 | public function assoc_key_values_to_array($ASSOC, $AKEY, $STOPONERROR = true) 124 | { 125 | $RETURN = []; 126 | 127 | // Make sure its $ASSOC is an array or it errors out. 128 | if (is_array($ASSOC)) { 129 | // Loop through the array of key=>value pairs 130 | foreach ($ASSOC as $KEY => $VALUE) { 131 | if (isset($VALUE[$AKEY]) && $VALUE[$AKEY] !== '') { 132 | if (isset($VALUE['uuid']) && $VALUE['uuid']) { 133 | // If the query returns a UUID, use that as our array key! 134 | $RETURN[$VALUE['uuid']] = $VALUE[$AKEY]; 135 | } else { 136 | // If the query does NOT return a UUID, use sequencial keys 137 | array_push($RETURN, $VALUE[$AKEY]); 138 | } 139 | } elseif ($STOPONERROR) { 140 | throw new \Exception("Assoc array value does not have key {$KEY}"); 141 | } 142 | } 143 | } 144 | 145 | return $RETURN; 146 | } 147 | 148 | // This builds a searchCriteria & returnedTags array pair for soap requests against CUCM AXL 149 | 150 | public function axl_search_return_array($SEARCH, $RETURN) 151 | { 152 | return [ 153 | 'searchCriteria' => $SEARCH, 154 | 'returnedTags' => $RETURN, 155 | ]; 156 | } 157 | 158 | // Kick off LDAP Sync Process in CUCM - Name of LDAP Dirctory and true to start or false to stop. 159 | 160 | public function do_ldap_sync($NAME, $BOOLEAN) 161 | { 162 | $SEARCH = ['name' => $NAME, 'sync' => $BOOLEAN]; 163 | // Search the CUCM for all phones 164 | $BASETIME = $this->microtimeTicks(); 165 | $RETURN = $this->SOAPCLIENT->doLdapSync($SEARCH); 166 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 167 | // log our soap call 168 | $this->log_soap_call('doLdapSync', $DIFFTIME, $SEARCH, $RETURN); 169 | 170 | if (!is_object($RETURN)) { 171 | throw new \Exception('SOAP reply is not an object'); 172 | } else { 173 | return $RETURN; 174 | } 175 | } 176 | 177 | public function get_ldap_sync_status($NAME) 178 | { 179 | $SEARCH = ['name' => $NAME]; 180 | // Search the CUCM for all phones 181 | $BASETIME = $this->microtimeTicks(); 182 | $RETURN = $this->SOAPCLIENT->getLdapSyncStatus($SEARCH); 183 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 184 | // log our soap call 185 | $this->log_soap_call('getLdapSyncStatus', $DIFFTIME, $SEARCH, $RETURN); 186 | 187 | if (!is_object($RETURN)) { 188 | throw new \Exception('SOAP reply is not an object'); 189 | } else { 190 | return $RETURN; 191 | } 192 | } 193 | 194 | public function reset_phone($NAME) 195 | { 196 | $SEARCH = ['name' => $NAME]; 197 | // Search the CUCM for all phones 198 | $BASETIME = $this->microtimeTicks(); 199 | $RETURN = $this->SOAPCLIENT->resetPhone($SEARCH); 200 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 201 | // log our soap call 202 | $this->log_soap_call('resetPhone', $DIFFTIME, $SEARCH, $RETURN); 203 | 204 | if (!is_object($RETURN)) { 205 | throw new \Exception('SOAP reply is not an object'); 206 | } else { 207 | return $RETURN; 208 | } 209 | } 210 | // Get a complete list of the names of all phones 211 | 212 | public function get_phone_names() 213 | { 214 | $SEARCH = $this->axl_search_return_array(['devicePoolName' => '%'], ['name' => '']); 215 | // Search the CUCM for all phones 216 | $BASETIME = $this->microtimeTicks(); 217 | $RETURN = $this->SOAPCLIENT->listPhone($SEARCH); 218 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 219 | // log our soap call 220 | $this->log_soap_call('listPhone', $DIFFTIME, $SEARCH, $RETURN); 221 | // Decode the reply into an array of results 222 | $RETURN = $this->decode_soap_reply($RETURN); 223 | // Turn the associative arrays into a single simensional array list 224 | $RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 225 | 226 | return $RETURN; 227 | } 228 | 229 | // Including specific fields to return in the list function. 230 | 231 | public function list_all_phones_summary_by_site($SITE) 232 | { 233 | $SEARCH = $this->axl_search_return_array(['devicePoolName' => "%{$SITE}%"], [ 234 | 'name' => '', 235 | 'description' => '', 236 | 'product' => '', 237 | 'callingSearchSpaceName' => '', 238 | 'devicePoolName' => '', 239 | 'locationName' => '', 240 | 'phoneTemplateName' => '', 241 | 'ownerUserName' => '', 242 | ]); 243 | // Search the CUCM for phones from Site Device Pool 244 | $BASETIME = $this->microtimeTicks(); 245 | $RETURN = $this->SOAPCLIENT->listPhone($SEARCH); 246 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 247 | // log our soap call 248 | $this->log_soap_call('listPhone', $DIFFTIME, $SEARCH, $RETURN); 249 | // Decode the reply into an array of results 250 | $RETURN = $this->decode_soap_reply($RETURN); 251 | // Turn the associative arrays into a single simensional array list 252 | //$RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 253 | 254 | return $RETURN; 255 | } 256 | 257 | // Search Phone by Name 258 | public function phone_search_by_name($NAME) 259 | { 260 | $SEARCH = $this->axl_search_return_array(['name' => "%{$NAME}%"], [ 261 | 'name' => '', 262 | 'description' => '', 263 | 'product' => '', 264 | 'callingSearchSpaceName' => '', 265 | 'devicePoolName' => '', 266 | 'locationName' => '', 267 | 'phoneTemplateName' => '', 268 | 'ownerUserName' => '', 269 | ]); 270 | // Search the CUCM for phones from Site Device Pool 271 | $BASETIME = $this->microtimeTicks(); 272 | $RETURN = $this->SOAPCLIENT->listPhone($SEARCH); 273 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 274 | // log our soap call 275 | $this->log_soap_call('listPhone', $DIFFTIME, $SEARCH, $RETURN); 276 | // Decode the reply into an array of results 277 | $RETURN = $this->decode_soap_reply($RETURN); 278 | // Turn the associative arrays into a single simensional array list 279 | //$RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 280 | 281 | return $RETURN; 282 | } 283 | 284 | // Search Phone by Key 285 | public function phone_search($KEY, $SEARCH) 286 | { 287 | /* 288 | $KEYS = 289 | ['name', 290 | 'description', 291 | 'protocol', 292 | 'callingSearchSpaceName', 293 | 'devicePoolName', 294 | 'securityProfileName'] 295 | 296 | */ 297 | $SEARCH = $this->axl_search_return_array([$KEY => "%{$SEARCH}%"], [ 298 | 'name' => '', 299 | 'description' => '', 300 | 'product' => '', 301 | 'callingSearchSpaceName' => '', 302 | 'devicePoolName' => '', 303 | 'locationName' => '', 304 | 'ownerUserName' => '', 305 | ]); 306 | // Search the CUCM for phones from Site Device Pool 307 | $BASETIME = $this->microtimeTicks(); 308 | $RETURN = $this->SOAPCLIENT->listPhone($SEARCH); 309 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 310 | // log our soap call 311 | $this->log_soap_call('listPhone', $DIFFTIME, $SEARCH, $RETURN); 312 | // Decode the reply into an array of results 313 | $RETURN = $this->decode_soap_reply($RETURN); 314 | // Turn the associative arrays into a single simensional array list 315 | //$RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 316 | 317 | return $RETURN; 318 | } 319 | 320 | // Get all the information regarding one specific phone by name 321 | 322 | public function get_phone_by_name($NAME) 323 | { 324 | $SEARCH = ['name' => $NAME]; 325 | $BASETIME = $this->microtimeTicks(); 326 | $RETURN = $this->SOAPCLIENT->getPhone($SEARCH); 327 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 328 | // log our soap call 329 | $this->log_soap_call('getPhone', $DIFFTIME, $SEARCH, $RETURN); 330 | // Decode the reply into an array of results 331 | $RETURN = $this->decode_soap_reply($RETURN); 332 | // Count the number of replies we recieved... 333 | $COUNT = count($RETURN); 334 | // It should be EXACTLY one result 335 | if ($COUNT !== 1) { 336 | throw new \Exception("Search returned {$COUNT} results, not exactly 1 as expected"); 337 | } 338 | // Strip off the outer array 339 | $RETURN = reset($RETURN); 340 | 341 | return $RETURN; 342 | } 343 | 344 | // Get an array of directory numbers by phone name 345 | 346 | public function get_directory_numbers_by_name($NAME) 347 | { 348 | // Get our phone by name from the previous function 349 | $PHONE = $this->get_phone_by_name($NAME); 350 | if (!isset($PHONE['lines'])) { 351 | throw new \Exception('Phone record does not contain the lines element'); 352 | } 353 | if (!is_array($PHONE['lines'])) { 354 | throw new \Exception('Phone record lines element is not an array'); 355 | } 356 | // Suck out the array of phone numbers 357 | $RETURN = reset($PHONE['lines']); 358 | // Turn them into a flat array of DIRNs 359 | $RETURN = $this->assoc_key_values_to_array($RETURN, 'dirn'); 360 | // Turn the DIRNs into patterns of phone numbers 361 | $RETURN = $this->assoc_key_values_to_array($RETURN, 'pattern'); 362 | 363 | return $RETURN; 364 | } 365 | 366 | // Get an array of every device pool name 367 | 368 | public function get_device_pool_names() 369 | { 370 | $SEARCH = $this->axl_search_return_array(['name' => '%'], ['name' => '']); 371 | // Search the CUCM for all device pools 372 | $BASETIME = $this->microtimeTicks(); 373 | $RETURN = $this->SOAPCLIENT->listDevicePool($SEARCH); 374 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 375 | // log our soap call 376 | $this->log_soap_call('listDevicePool', $DIFFTIME, $SEARCH, $RETURN); 377 | // Decode the reply into an array of results 378 | $RETURN = $this->decode_soap_reply($RETURN); 379 | // Turn the associative arrays into a single simensional array list 380 | $RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 381 | 382 | return $RETURN; 383 | } 384 | 385 | // Get an array of route plans by some search string 386 | 387 | public function get_route_plan_by_name($pattern, $partition = '%') 388 | { 389 | $SEARCH = $this->axl_search_return_array(['dnOrPattern' => $pattern, 'partition' => $partition], 390 | ['dnOrPattern' => '', 'partition' => '', 'type' => '', 'routeDetail' => '']); 391 | // Search the CUCM for all device pools 392 | $BASETIME = $this->microtimeTicks(); 393 | $RETURN = $this->SOAPCLIENT->listRoutePlan($SEARCH); 394 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 395 | // log our soap call 396 | $this->log_soap_call('listRoutePlan', $DIFFTIME, $SEARCH, $RETURN); 397 | // Decode the reply into an array of results 398 | $RETURN = $this->decode_soap_reply($RETURN); 399 | // Turn the associative arrays into a single simensional array list 400 | //$RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 401 | 402 | return $RETURN; 403 | } 404 | 405 | // Get an array of route plans by some search string 406 | 407 | public function get_all_users() 408 | { 409 | $SEARCH = $this->axl_search_return_array(['userid' => '%'], 410 | ['firstName' => '', 'lastName' => '', 'userid' => '', 'primaryExtension' => '']); 411 | // Search the CUCM for all device pools 412 | $BASETIME = $this->microtimeTicks(); 413 | $RETURN = $this->SOAPCLIENT->listUser($SEARCH); 414 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 415 | // log our soap call 416 | $this->log_soap_call('listUser', $DIFFTIME, $SEARCH, $RETURN); 417 | // Decode the reply into an array of results 418 | $RETURN = $this->decode_soap_reply($RETURN); 419 | // Turn the associative arrays into a single simensional array list 420 | //$RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 421 | 422 | return $RETURN; 423 | } 424 | 425 | 426 | public function list_all_usernames() 427 | { 428 | $SEARCH = $this->axl_search_return_array(['userid' => '%'], 429 | ['userid' => '']); 430 | // Search the CUCM for all device pools 431 | $BASETIME = $this->microtimeTicks(); 432 | $RETURN = $this->SOAPCLIENT->listUser($SEARCH); 433 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 434 | // log our soap call 435 | $this->log_soap_call('listUser', $DIFFTIME, $SEARCH, $RETURN); 436 | // Decode the reply into an array of results 437 | $RETURN = $this->decode_soap_reply($RETURN); 438 | // Turn the associative arrays into a single simensional array list 439 | //$RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 440 | 441 | return $RETURN; 442 | } 443 | 444 | 445 | public function get_user_by_username($USERNAME) 446 | { 447 | $SEARCH = ['userid' => $USERNAME]; 448 | 449 | $BASETIME = $this->microtimeTicks(); 450 | $RETURN = $this->SOAPCLIENT->getUser($SEARCH); 451 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 452 | // log our soap call 453 | $this->log_soap_call('getUser', $DIFFTIME, $SEARCH, $RETURN); 454 | // Decode the reply into an array of results 455 | $RETURN = $this->decode_soap_reply($RETURN); 456 | // Count the number of replies we recieved... 457 | $COUNT = count($RETURN); 458 | // It should be EXACTLY one result 459 | if ($COUNT !== 1) { 460 | throw new \Exception("Search returned {$COUNT} results, not exactly 1 as expected"); 461 | } 462 | // Strip off the outer array 463 | $RETURN = reset($RETURN); 464 | 465 | return $RETURN; 466 | } 467 | 468 | public function add_user($DATA) 469 | { 470 | $TYPE = "User"; 471 | // Only the FIRST letter in the type needs to be lower case 472 | // so we cant do $TYPE = strtolower($TYPE); 473 | $FUNCTION = 'add'.$TYPE; 474 | $TYPE = lcfirst($TYPE); 475 | $QUERY = [$TYPE => $DATA]; 476 | //print_r($QUERY); 477 | $BASETIME = $this->microtimeTicks(); 478 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 479 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 480 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 481 | $RETURN = $this->object_to_assoc($RETURN); 482 | $RETURN = reset($RETURN); 483 | return $RETURN; 484 | } 485 | 486 | // Manage the list of types valid for our generalized dosomething_objecttypexyz_bysomething($1,$2) 487 | 488 | public function object_types() 489 | { 490 | // Valid object types this function works for 491 | $TYPES = ['DevicePool', 492 | 'Srst', 493 | 'RoutePartition', 494 | 'Css', 495 | 'Location', 496 | 'Region', 497 | 'CallManagerGroup', 498 | 'ConferenceBridge', 499 | 'Mtp', 500 | 'MediaResourceGroup', 501 | 'MediaResourceList', 502 | 'H323Gateway', 503 | 'RouteGroup', 504 | 'RouteList', 505 | 'RoutePattern', 506 | 'TransPattern', 507 | 'ApplicationDialRules', 508 | 'CallingPartyTransformationPattern', 509 | 'CalledPartyTransformationPattern', 510 | 'DateTimeGroup', 511 | 'Phone', 512 | 'Line', 513 | 'CtiRoutePoint', 514 | 'HuntPilot', 515 | 'RemoteDestinationProfile', 516 | 'CallPark' 517 | ]; 518 | 519 | return $TYPES; 520 | } 521 | 522 | // Get an array of site names 523 | 524 | public function get_site_names() 525 | { 526 | // Get the list of device pools 527 | $DEVICEPOOLS = $this->get_device_pool_names(); 528 | $SITES = []; 529 | // Loop through all of the device pools 530 | foreach ($DEVICEPOOLS as $DP) { 531 | // Detect the DP_SITECODE format and put it into an array 532 | $REGEX = "/^DP_(\w+)/"; 533 | if (preg_match($REGEX, $DP, $HITS)) { 534 | array_push($SITES, $HITS[1]); 535 | } else { 536 | //print "{$DP} did not match {$REGEX}!
\n"; 537 | } 538 | } 539 | // Return our array of sites 540 | return $SITES; 541 | } 542 | 543 | public function get_remoteDestinationProfiles() 544 | { 545 | $SEARCH = $this->axl_search_return_array(['name' => '%'], 546 | ['name' => '', 'model' => '', 'callingSearchSpaceName' => '', 'devicePoolName' => '', 'userId' => '', 'uuid' => '']); 547 | $BASETIME = $this->microtimeTicks(); 548 | $RETURN = $this->SOAPCLIENT->listRemoteDestinationProfile($SEARCH); 549 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 550 | // log our soap call 551 | $this->log_soap_call('listRemoteDestinationProfile', $DIFFTIME, $SEARCH, $RETURN); 552 | // Decode the reply into an array of results 553 | $RETURN = $this->decode_soap_reply($RETURN); 554 | // Turn the associative arrays into a single simensional array list 555 | $RETURN = $this->assoc_key_values_to_array($RETURN, 'name'); 556 | 557 | return $RETURN; 558 | } 559 | 560 | public function get_remoteDestinationProfilesbySite($SITE) 561 | { 562 | $SEARCH = $this->axl_search_return_array(['name' => '%'], 563 | ['name' => '', 'model' => '', 'callingSearchSpaceName' => '', 'devicePoolName' => '', 'userId' => '', 'uuid' => '']); 564 | $BASETIME = $this->microtimeTicks(); 565 | $RETURN = $this->SOAPCLIENT->listRemoteDestinationProfile($SEARCH); 566 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 567 | // log our soap call 568 | $this->log_soap_call('listRemoteDestinationProfile', $DIFFTIME, $SEARCH, $RETURN); 569 | // Decode the reply into an array of results 570 | $RETURN = $this->decode_soap_reply($RETURN); 571 | $RETR = []; 572 | 573 | foreach ($RETURN as $RDP) { 574 | //print_r($RDP['devicePoolName']); 575 | //return $RDP; 576 | if (preg_match("/{$SITE}/", $RDP['devicePoolName']['_'])) { 577 | $RETR[] = $RDP; 578 | } 579 | } 580 | // Turn the associative arrays into a single simensional array list 581 | $RETURN = $this->assoc_key_values_to_array($RETR, 'name'); 582 | 583 | return $RETURN; 584 | } 585 | 586 | // LIST STUFF IN SITES 587 | 588 | // Generalized function to return any type of object using the list/search functionality for a site 589 | 590 | public function get_object_type_by_site($SITE, $TYPE) 591 | { 592 | // Get our valid object types 593 | $TYPES = $this->object_types(); 594 | 595 | // Check to see if the one we were passed is valid for this function 596 | if (!in_array($TYPE, $TYPES)) { 597 | throw new \Exception("Object type provided {$TYPE} is not supported"); 598 | } 599 | 600 | // Lines is a special case due to highly nested indirect nature of its search selector relationships 601 | if ($TYPE == 'Line') { 602 | return $this->get_lines_by_site($SITE); 603 | } 604 | //$TYPES = array_diff($TYPES, ['Line']); 605 | 606 | // This is the default search and return criteria for MOST object types. There are a few exceptions 607 | $FIND = ['name' => "%{$SITE}%"]; 608 | $RETR = ['name' => '']; 609 | // Phone search uses a different search name field 610 | if ($TYPE == 'Phone') { 611 | $FIND = ['devicePoolName' => "%{$SITE}%"]; 612 | } elseif ($TYPE == 'CtiRoutePoint') { 613 | $FIND = ['devicePoolName' => "%{$SITE}%"]; 614 | } elseif ($TYPE == 'H323Gateway') { 615 | $FIND = ['devicePoolName' => "%{$SITE}%"]; 616 | // So does route pattern search and returns a different field - Need to search by specific Partition; 617 | } elseif ($TYPE == 'RoutePattern') { 618 | $FIND = ['routePartitionName' => "%{$SITE}%"]; 619 | $RETR = ['pattern' => '', 'routePartitionName' => '']; 620 | // So does translation pattern search and returns a different field 621 | } elseif ($TYPE == 'TransPattern') { 622 | $FIND = ['routePartitionName' => "%{$SITE}%"]; 623 | $RETR = ['pattern' => '']; 624 | // So does CallingPartyTransformationPattern pattern search and returns a different field 625 | } elseif ($TYPE == 'CallingPartyTransformationPattern') { 626 | $FIND = ['routePartitionName' => "%{$SITE}%"]; 627 | $RETR = ['pattern' => '']; 628 | // So does CalledPartyTransformationPattern pattern search and returns a different field 629 | } elseif ($TYPE == 'CalledPartyTransformationPattern') { 630 | $FIND = ['routePartitionName' => "%{$SITE}%"]; 631 | $RETR = ['pattern' => '']; 632 | } elseif ($TYPE == 'HuntPilot') { 633 | $FIND = ['routePartitionName' => "%{$SITE}%"]; 634 | $RETR = ['pattern' => '']; 635 | } elseif ($TYPE == 'CallPark') { 636 | $FIND = ['routePartitionName' => "%{$SITE}%"]; 637 | $RETR = ['pattern' => '']; 638 | } elseif ($TYPE == 'RemoteDestinationProfile') { 639 | $RETR = $this->get_remoteDestinationProfilesbySite($SITE); 640 | 641 | return $RETR; 642 | } 643 | 644 | $SEARCH = $this->axl_search_return_array($FIND, $RETR); 645 | 646 | $FUNCTION = 'list'.$TYPE; 647 | // Search the CUCM for matching SRST devices 648 | $BASETIME = $this->microtimeTicks(); 649 | $RETURN = $this->SOAPCLIENT->$FUNCTION($SEARCH); 650 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 651 | // log our soap call 652 | $this->log_soap_call($FUNCTION, $DIFFTIME, $SEARCH, $RETURN); 653 | // Decode the reply into an array of results 654 | $RETURN = $this->decode_soap_reply($RETURN); 655 | 656 | // Turn the associative arrays into a single simensional array list 657 | $AKEYS = array_keys($RETR); 658 | $RESET = reset($AKEYS); 659 | $RETURN = $this->assoc_key_values_to_array($RETURN, $RESET); 660 | 661 | return $RETURN; 662 | } 663 | 664 | // List lines by site is indirect and dumb. phones are identified by device pool name of DP_SITE, lines are identified by owning phones. 665 | // This function will need to get every phone in a device pool and then build a list of every LINE that is returned. 666 | public function get_lines_by_site($SITE) 667 | { 668 | // Get all the phone object uuid=>names for a given site (based on device pool) 669 | $PHONES = $this->get_object_type_by_site($SITE, 'Phone'); 670 | $LINES = []; 671 | // Loop through our phones at a site and use the UUID to get its detailed object information 672 | foreach ($PHONES as $UUID => $NAME) { 673 | $PHONE = $this->get_object_type_by_uuid($UUID, 'Phone'); 674 | // if there are lines in the phone go get the uuid and name for each line dirn 675 | if (isset($PHONE['lines']) && is_array($PHONE['lines']) && count($PHONE['lines'])) { 676 | // loop through each line on the phone and suck out the uuid and dial pattern 677 | foreach ($PHONE['lines'] as $PHONELINE) { 678 | // If the phone has a dirn element with elements 679 | if (isset($PHONELINE['dirn']) && is_array($PHONELINE['dirn']) && count($PHONELINE['dirn'])) { 680 | // And the dirn has a uuid and pattern with value 681 | if (isset($PHONELINE['dirn']['pattern']) && $PHONELINE['dirn']['pattern'] && isset($PHONELINE['dirn']['uuid']) && $PHONELINE['dirn']['uuid']) { 682 | // Save this line to the list of site lines we return 683 | $LINES[$PHONELINE['dirn']['uuid']] = $PHONELINE['dirn']['pattern']; 684 | } 685 | } 686 | } 687 | } 688 | } 689 | 690 | return $LINES; 691 | } 692 | 693 | // Get Phone Line Details of the phone by Name 694 | public function get_lines_details_by_phone_name($NAME) 695 | { 696 | // Get all the phone object uuid=>names for a given site (based on device pool) 697 | $LINES = []; 698 | 699 | // get phone Line detailed object information 700 | $PHONE = $this->get_object_type_by_name($NAME, 'Phone'); 701 | // if there are lines in the phone go get the uuid and name for each line dirn 702 | if (isset($PHONE['lines']) && is_array($PHONE['lines']) && count($PHONE['lines'])) { 703 | // loop through each line on the phone and suck out the uuid and dial pattern 704 | foreach ($PHONE['lines'] as $PHONELINE) { 705 | if (isset($PHONELINE['dirn']['pattern']) && $PHONELINE['dirn']['pattern'] && isset($PHONELINE['dirn']['uuid']) && $PHONELINE['dirn']['uuid']) { 706 | // Phone has single linee 707 | $UUID = $PHONELINE['dirn']['uuid']; 708 | $LINE = $this->get_object_type_by_uuid($UUID, 'Line'); 709 | $LINES[$PHONELINE['dirn']['uuid']] = $LINE; 710 | } else { 711 | // Phone has multiple lines 712 | foreach ($PHONELINE as $SUBLINE) { 713 | if (isset($SUBLINE['dirn']['pattern']) && $SUBLINE['dirn']['pattern'] && isset($SUBLINE['dirn']['uuid']) && $SUBLINE['dirn']['uuid']) { 714 | // Save this line to the list of site lines we return 715 | //$LINES[$SUBLINE['dirn']['uuid']] = $SUBLINE['dirn']['pattern']; 716 | $UUID = $SUBLINE['dirn']['uuid']; 717 | $LINE = $this->get_object_type_by_uuid($UUID, 'Line'); 718 | $LINES[$SUBLINE['dirn']['uuid']] = $LINE; 719 | } 720 | } 721 | } 722 | } 723 | } 724 | 725 | return $LINES; 726 | } 727 | 728 | // This returns an associative array for each of the above types 729 | 730 | public function get_all_object_types_by_site($SITE) 731 | { 732 | // Get our valid object types 733 | $TYPES = $this->object_types(); 734 | 735 | // Do not get these objects by site. - They need to be requested directly. 736 | $DISCARD_TYPES = [ 737 | 'Phone', 738 | 'Line', 739 | //'CtiRoutePoint', 740 | ]; 741 | 742 | $RETURN = []; 743 | foreach ($TYPES as $TYPE) { 744 | if (in_array($TYPE, $DISCARD_TYPES)) { 745 | continue; 746 | } 747 | if (php_sapi_name() === 'cli') { 748 | //print "Getting {$SITE}s {$TYPE}...".PHP_EOL; 749 | } 750 | /* 751 | if ($TYPE == 'Line') { 752 | continue; 753 | }*/ 754 | try { 755 | $RETURN[$TYPE] = $this->get_object_type_by_site($SITE, $TYPE); 756 | } catch (\Exception $E) { 757 | $RETURN[$TYPE] = []; 758 | } 759 | } 760 | 761 | return $RETURN; 762 | } 763 | 764 | public function get_all_object_type_details_by_site($SITE) 765 | { 766 | // Get our valid object types 767 | $TYPES = $this->object_types(); 768 | // Do not get these objects by site. - They need to be requested directly. 769 | $DISCARD_TYPES = [ 770 | 'Phone', 771 | 'Line', 772 | //'CtiRoutePoint', 773 | ]; 774 | 775 | $RETURN = []; 776 | foreach ($TYPES as $TYPE) { 777 | if (in_array($TYPE, $DISCARD_TYPES)) { 778 | continue; 779 | } 780 | 781 | try { 782 | $RETURN[$TYPE] = $this->get_object_type_by_site($SITE, $TYPE); 783 | foreach ($RETURN[$TYPE] as $INDEX => $NAME) { 784 | unset($RETURN[$TYPE][$INDEX]); 785 | $RETURN[$TYPE][$INDEX] = $this->get_object_type_by_uuid($INDEX, $TYPE); 786 | } 787 | } catch (\Exception $E) { 788 | // If we encounter a specific error getting one TYPE of thing, continue on to the NEXT type of thing 789 | $RETURN[$TYPE] = []; 790 | } 791 | } 792 | 793 | return $RETURN; 794 | } 795 | 796 | // GET DETAILED STUFF 797 | 798 | public function get_object_type_by_name($NAME, $TYPE) 799 | { 800 | // Get our valid object types 801 | $TYPES = $this->object_types(); 802 | // TransPattern is not valid for get-item-by-NAME, must use UUID or a combination of name and routepartitionname 803 | $TYPES = array_diff($TYPES, ['TransPattern']); 804 | // Lines is not valid for get-item-by-name, must be UUID 805 | $TYPES = array_diff($TYPES, ['Line']); 806 | // Check to see if the one we were passed is valid for this function 807 | if (!in_array($TYPE, $TYPES)) { 808 | throw new \Exception("Object type provided {$TYPE} is not supported"); 809 | } 810 | 811 | $QUERY = ['name' => $NAME]; 812 | $FUNCTION = 'get'.$TYPE; 813 | $BASETIME = $this->microtimeTicks(); 814 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 815 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 816 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 817 | $RETURN = $this->decode_soap_reply($RETURN); 818 | $RETURN = reset($RETURN); 819 | 820 | return $RETURN; 821 | } 822 | 823 | public function get_object_type_by_pattern_and_partition($PATTERN, $PARTITION, $TYPE) 824 | { 825 | // Type must be a member of the TYPES Array for this function 826 | 827 | // Get our valid object types 828 | $TYPES = [ 829 | 'TransPattern', 830 | 'Line', 831 | 'RoutePattern', 832 | ]; 833 | 834 | // Check to see if the one we were passed is valid for this function 835 | if (!in_array($TYPE, $TYPES)) { 836 | throw new \Exception("Object type provided {$TYPE} is not supported"); 837 | } 838 | 839 | $QUERY = ['pattern' => $PATTERN, 'routePartitionName' => $PARTITION]; 840 | $FUNCTION = 'get'.$TYPE; 841 | $BASETIME = $this->microtimeTicks(); 842 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 843 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 844 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 845 | $RETURN = $this->decode_soap_reply($RETURN); 846 | $RETURN = reset($RETURN); 847 | 848 | return $RETURN; 849 | } 850 | 851 | public function get_object_type_by_uuid($UUID, $TYPE) 852 | { 853 | // Get our valid object types 854 | $TYPES = $this->object_types(); 855 | // Check to see if the one we were passed is valid for this function 856 | if (!in_array($TYPE, $TYPES)) { 857 | throw new \Exception("Object type provided {$TYPE} is not supported"); 858 | } 859 | 860 | $QUERY = ['uuid' => $UUID]; 861 | $FUNCTION = 'get'.$TYPE; 862 | $BASETIME = $this->microtimeTicks(); 863 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 864 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 865 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 866 | $RETURN = $this->decode_soap_reply($RETURN); 867 | $RETURN = reset($RETURN); 868 | 869 | return $RETURN; 870 | } 871 | 872 | // DELETE STUFF 873 | 874 | // Only way I want to support removing items is by UUID, this is for safety because object names may not be unique 875 | 876 | public function delete_object_type_by_uuid($UUID, $TYPE) 877 | { 878 | // Get our valid object types 879 | $TYPES = $this->object_types(); 880 | // Check to see if the one we were passed is valid for this function 881 | if (!in_array($TYPE, $TYPES)) { 882 | throw new \Exception("Object type provided {$TYPE} is not supported"); 883 | } 884 | 885 | $QUERY = ['uuid' => $UUID]; 886 | $FUNCTION = 'remove'.$TYPE; 887 | $BASETIME = $this->microtimeTicks(); 888 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 889 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 890 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 891 | 892 | return $RETURN; 893 | } 894 | 895 | public function delete_all_object_types_by_site($SITE) 896 | { 897 | // This works - but do not call it! 898 | /* throw new \Exception("DO NOT CALL THIS FUNCTION"); 899 | return; 900 | /**/ 901 | 902 | $RESULT = []; 903 | 904 | // The order of this list is critical to successfully remove all the objects in a given site... 905 | 906 | $ORDER = [ 907 | 'CallPark', 908 | 'RemoteDestinationProfile', 909 | 'HuntPilot', 910 | 'CtiRoutePoint', 911 | 'CalledPartyTransformationPattern', 912 | 'CallingPartyTransformationPattern', 913 | 'ApplicationDialRules', 914 | 'TransPattern', 915 | 'updateDevicePool', 916 | 'RoutePattern', 917 | 'RouteList', 918 | 'RouteGroup', 919 | 'H323Gateway', 920 | 'MediaResourceList', 921 | 'MediaResourceGroup', 922 | 'Mtp', 923 | 'ConferenceBridge', 924 | 'DevicePool', 925 | 'CallManagerGroup', 926 | 'Region', 927 | 'Location', 928 | 'Css', 929 | 'RoutePartition', 930 | 'Srst', 931 | ]; 932 | $OBJECTS = $this->get_all_object_types_by_site($SITE); 933 | foreach ($ORDER as $STEP) { 934 | // This step is special 935 | if ($STEP == 'updateDevicePool') { 936 | // Go through all the device pools 937 | foreach ($OBJECTS['DevicePool'] as $UUID => $DP) { 938 | // Pull the device pool out of the database - do i even need to do this? 939 | //$DP = $this->get_object_type_by_uuid($UUID,'DevicePool'); 940 | // Build a query to blank out the mediaResourceListName and localRouteGroup['value'] properties 941 | $QUERY = ['uuid' => $UUID]; 942 | $QUERY['mediaResourceListName'] = ''; 943 | $QUERY['localRouteGroup'] = ['name' => 'Standard Local Route Group', 'value' => '']; 944 | $BASETIME = $this->microtimeTicks(); 945 | // Remove references to objects we plan to delete shortly from this 946 | $RETURN = $this->SOAPCLIENT->updateDevicePool($QUERY); 947 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 948 | $this->log_soap_call('updateSrst', $DIFFTIME, $QUERY, $RETURN); 949 | // Now we can continue deleting the other object types 950 | } 951 | } else { 952 | foreach ($OBJECTS[$STEP] as $UUID => $NAME) { 953 | //echo "Attempting to delete object type {$STEP} name {$NAME} UUID {$UUID}"; 954 | try { 955 | $RESULT[$STEP][$UUID] = $this->delete_object_type_by_uuid($UUID, $STEP); 956 | } catch (\Exception $E) { 957 | $RESULT[$STEP][$UUID] = "Error deleteing object! {$E->getmessage()}"; 958 | } 959 | } 960 | } 961 | } 962 | 963 | return $RESULT; 964 | } 965 | 966 | // ADD STUFF 967 | 968 | // This generalized add function expects $DATA to be correct for $TYPE objects 969 | 970 | public function add_object_type_by_assoc($DATA, $TYPE) 971 | { 972 | // Get our valid object types 973 | $TYPES = $this->object_types(); 974 | // Check to see if the one we were passed is valid for this function 975 | if (!in_array($TYPE, $TYPES)) { 976 | throw new \Exception("Object type provided {$TYPE} is not supported"); 977 | } 978 | 979 | // Only the FIRST letter in the type needs to be lower case 980 | // so we cant do $TYPE = strtolower($TYPE); 981 | $FUNCTION = 'add'.$TYPE; 982 | $TYPE = lcfirst($TYPE); 983 | $QUERY = [$TYPE => $DATA]; 984 | //print_r($QUERY); 985 | $BASETIME = $this->microtimeTicks(); 986 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 987 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 988 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 989 | $RETURN = $this->object_to_assoc($RETURN); 990 | $RETURN = reset($RETURN); 991 | 992 | return $RETURN; 993 | } 994 | 995 | // UPDATE STUFF 996 | 997 | // This generalized update function expects $DATA to be correct for $TYPE objects 998 | 999 | public function update_object_type_by_assoc($DATA, $TYPE) 1000 | { 1001 | // Get our valid object types 1002 | $TYPES = $this->object_types(); 1003 | // Check to see if the one we were passed is valid for this function 1004 | if (!in_array($TYPE, $TYPES)) { 1005 | throw new \Exception("Object type provided {$TYPE} is not supported"); 1006 | } 1007 | // There may be a case where the name is not actually called name 1008 | $NAMEFIELD = 'name'; 1009 | if (!isset($DATA[$NAMEFIELD]) || !$DATA[$NAMEFIELD]) { 1010 | throw new \Exception('Data does not contain a valid name to update'); 1011 | } 1012 | $NAME = $DATA[$NAMEFIELD]; 1013 | // Get their object information out of the database 1014 | $OBJECT = $this->get_object_type_by_name($NAME, $TYPE); 1015 | //print "DUMP OF OBJECT WE FOUND TO EDIT:\n"; dumper($OBJECT); 1016 | // TODO: Make sure this is a valid object? Do some other checks? 1017 | // Force the query to use our name as search criteria 1018 | $QUERY = [$NAMEFIELD => $NAME]; 1019 | // Loop through object keys and see if the value passed has changed 1020 | foreach ($OBJECT as $KEY => $VALUE) { 1021 | // Make sure the object key val pair is defined in the new data passed 1022 | // AND check if the value of the new data has changed from the original 1023 | if (isset($DATA[$KEY]) && $DATA[$KEY] != $VALUE) { 1024 | // Build our update query of different values 1025 | $QUERY[$KEY] = $DATA[$KEY]; 1026 | } elseif (isset($DATA['addMembers'])) { 1027 | // Add it to query if the addMembersis set. This is for CSS updates 1028 | $QUERY['addMembers'] = $DATA['addMembers']; 1029 | } elseif (isset($DATA['removeMembers'])) { 1030 | // Add it to query if the removeMembers is set. This is for CSS updates 1031 | $QUERY['removeMembers'] = $DATA['removeMembers']; 1032 | } elseif (isset($DATA['newName'])) { 1033 | // Add it to query if the newName is set. This is for name changes. 1034 | $QUERY['newName'] = $DATA['newName']; 1035 | } 1036 | } 1037 | //print "QUERY CALCULATED ON OBJECT TO UPDATE:\n"; dumper($QUERY); 1038 | // Update our object 1039 | $FUNCTION = 'update'.$TYPE; 1040 | $BASETIME = $this->microtimeTicks(); 1041 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 1042 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 1043 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 1044 | $RETURN = $this->object_to_assoc($RETURN); 1045 | $RETURN = reset($RETURN); 1046 | 1047 | return $RETURN; 1048 | } 1049 | 1050 | public function update_object_type_by_uuid_assoc($DATA, $TYPE) 1051 | { 1052 | // Get our valid object types 1053 | $TYPES = $this->object_types(); 1054 | // Check to see if the one we were passed is valid for this function 1055 | if (!in_array($TYPE, $TYPES)) { 1056 | throw new \Exception("Object type provided {$TYPE} is not supported"); 1057 | } 1058 | // There may be a case where the name is not actually called name 1059 | $NAMEFIELD = 'uuid'; 1060 | if (!isset($DATA[$NAMEFIELD]) || !$DATA[$NAMEFIELD]) { 1061 | throw new \Exception('Data does not contain a valid uuid to update'); 1062 | } 1063 | $NAME = $DATA[$NAMEFIELD]; 1064 | // Get their object information out of the database 1065 | $OBJECT = $this->get_object_type_by_uuid($NAME, $TYPE); 1066 | //print "DUMP OF OBJECT WE FOUND TO EDIT:\n"; dumper($OBJECT); 1067 | // TODO: Make sure this is a valid object? Do some other checks? 1068 | // Force the query to use our name as search criteria 1069 | $QUERY = [$NAMEFIELD => $NAME]; 1070 | // Loop through object keys and see if the value passed has changed 1071 | foreach ($OBJECT as $KEY => $VALUE) { 1072 | // Make sure the object key val pair is defined in the new data passed 1073 | // AND check if the value of the new data has changed from the original 1074 | if (isset($DATA[$KEY]) && $DATA[$KEY] != $VALUE) { 1075 | // Build our update query of different values 1076 | $QUERY[$KEY] = $DATA[$KEY]; 1077 | } elseif (isset($DATA['addMembers'])) { 1078 | // Add it to query if the addMembersis set. This is for CSS updates 1079 | $QUERY['addMembers'] = $DATA['addMembers']; 1080 | } elseif (isset($DATA['removeMembers'])) { 1081 | // Add it to query if the removeMembers is set. This is for CSS updates 1082 | $QUERY['removeMembers'] = $DATA['removeMembers']; 1083 | } elseif (isset($DATA['newName'])) { 1084 | // Add it to query if the newName is set. This is for name changes. 1085 | $QUERY['newName'] = $DATA['newName']; 1086 | } 1087 | } 1088 | //print "QUERY CALCULATED ON OBJECT TO UPDATE:\n"; dumper($QUERY); 1089 | // Update our object 1090 | $FUNCTION = 'update'.$TYPE; 1091 | $BASETIME = $this->microtimeTicks(); 1092 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 1093 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 1094 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 1095 | $RETURN = $this->object_to_assoc($RETURN); 1096 | $RETURN = reset($RETURN); 1097 | 1098 | return $RETURN; 1099 | } 1100 | 1101 | public function update_object_type_by_pattern_and_partition($DATA, $TYPE) 1102 | { 1103 | if (!$DATA['pattern']) { 1104 | throw new \Exception('No Pattern set'); 1105 | } else { 1106 | $PATTERN = $DATA['pattern']; 1107 | } 1108 | 1109 | if (!$DATA['routePartitionName']) { 1110 | throw new \Exception('No Partition set'); 1111 | } else { 1112 | $PARTITION = $DATA['routePartitionName']; 1113 | } 1114 | 1115 | // Get our valid object types 1116 | $TYPES = $this->object_types(); 1117 | // Check to see if the one we were passed is valid for this function 1118 | if (!in_array($TYPE, $TYPES)) { 1119 | throw new \Exception("Object type provided {$TYPE} is not supported"); 1120 | } 1121 | 1122 | // Get their object information out of the database 1123 | $OBJECT = $this->get_object_type_by_pattern_and_partition($PATTERN, $PARTITION, $TYPE); 1124 | //print "DUMP OF OBJECT WE FOUND TO EDIT:\n"; dumper($OBJECT); 1125 | 1126 | // TODO: Make sure this is a valid object? Do some other checks? 1127 | 1128 | // Force the query to use our name as search criteria 1129 | $QUERY = ['pattern' => $PATTERN, 'routePartitionName' => $PARTITION]; 1130 | // Loop through object keys and see if the value passed has changed 1131 | foreach ($OBJECT as $KEY => $VALUE) { 1132 | // Make sure the object key val pair is defined in the new data passed 1133 | // AND check if the value of the new data has changed from the original 1134 | if (isset($DATA[$KEY]) && $DATA[$KEY] != $VALUE) { 1135 | // Build our update query of different values 1136 | $QUERY[$KEY] = $DATA[$KEY]; 1137 | } elseif (isset($DATA['addMembers'])) { 1138 | // Add it to query if the addMembersis set. This is for CSS updates 1139 | $QUERY['addMembers'] = $DATA['addMembers']; 1140 | } elseif (isset($DATA['removeMembers'])) { 1141 | // Add it to query if the removeMembers is set. This is for CSS updates 1142 | $QUERY['removeMembers'] = $DATA['removeMembers']; 1143 | } 1144 | } 1145 | //print "QUERY CALCULATED ON OBJECT TO UPDATE:\n"; dumper($QUERY); 1146 | // Update our object 1147 | $FUNCTION = 'update'.$TYPE; 1148 | $BASETIME = $this->microtimeTicks(); 1149 | $RETURN = $this->SOAPCLIENT->$FUNCTION($QUERY); 1150 | $DIFFTIME = $this->microtimeTicks() - $BASETIME; 1151 | $this->log_soap_call($FUNCTION, $DIFFTIME, $QUERY, $RETURN); 1152 | $RETURN = $this->object_to_assoc($RETURN); 1153 | $RETURN = reset($RETURN); 1154 | 1155 | return $RETURN; 1156 | } 1157 | } 1158 | --------------------------------------------------------------------------------