PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/OnApp.php

https://github.com/Spencerx/OnApp-PHP-Wrapper-External
PHP | 1680 lines | 800 code | 169 blank | 711 comment | 78 complexity | 0518c6fe3bc551b721cc3114f992156a MD5 | raw file
  1. <?php
  2. /**
  3. * Current OnApp PHP API wrapper version
  4. */
  5. define( 'ONAPP_VERSION', '2.0' );
  6. /**
  7. * The OnApp class uses this variable to define the Proxy server used by cURL
  8. */
  9. define( 'ONAPP_OPTION_CURL_PROXY', 'proxy' );
  10. /**
  11. * The OnApp class uses this variable to define the URL to the API used by cURL
  12. */
  13. define( 'ONAPP_OPTION_CURL_URL', 'url' );
  14. /**
  15. * The OnApp class uses this variable to define the data type which would help transfer data between the client and the API server
  16. *
  17. * Possible values:
  18. * - xml (default)
  19. * - json (will be available after the parcer is created)
  20. */
  21. define( 'ONAPP_OPTION_API_TYPE', 'data_type' );
  22. /**
  23. * The OnApp class uses this variable to define the charsets used to transfer data between the client and the API server
  24. *
  25. * Possible values:
  26. * - charset=utf-8 (default)
  27. */
  28. define( 'ONAPP_OPTION_API_CHARSET', 'charset' );
  29. /**
  30. * The OnApp class uses this value to define the content type used to transfer data between the client and the API server
  31. *
  32. * Possible values:
  33. * - application/xml (default)
  34. * - application/json (will be available after the Json parcer is created)
  35. */
  36. define( 'ONAPP_OPTION_API_CONTENT', 'content' );
  37. /**
  38. * TODO add description
  39. */
  40. define( 'ONAPP_OPTION_DEBUG_MODE', 'debug_mode' );
  41. /**
  42. * The OnApp class uses this field name to map this field in the API response and variable in the class
  43. * The field name is used to unserialize the API server response to the necessary class.
  44. */
  45. define( 'ONAPP_FIELD_MAP', 'map' );
  46. /**
  47. * The field name that stands for the mapped field type in the API response
  48. *
  49. * The field is used to unserialize the object into API request.
  50. * Possible values:
  51. * - integer
  52. * - ...
  53. */
  54. define( 'ONAPP_FIELD_TYPE', 'type' );
  55. /**
  56. * The field name that stands for the field access in the API response
  57. *
  58. * Used to unserialize the object into API request.
  59. * Possible values:
  60. * - true
  61. * - false
  62. */
  63. define( 'ONAPP_FIELD_READ_ONLY', 'read_only' );
  64. /**
  65. * The flag to exclude this field from sending request
  66. *
  67. * Possible values:
  68. * - true
  69. * - false
  70. */
  71. define( 'ONAPP_FIELD_SKIP_FROM_REQUEST', 'skip' );
  72. /**
  73. * The field name that specifies if it is necessary to be used in the API request when new objects are created or existing edited
  74. *
  75. * Possible values:
  76. * - true
  77. * - false
  78. */
  79. define( 'ONAPP_FIELD_REQUIRED', 'required' );
  80. /**
  81. * The field name that stands for the default field value
  82. *
  83. * The field name is used to unserialize if the field was changed or not loaded.
  84. */
  85. define( 'ONAPP_FIELD_DEFAULT_VALUE', 'default' );
  86. /**
  87. * Specify field type to serialize and unserialize obgect using their name
  88. */
  89. define( 'ONAPP_FIELD_CLASS', 'class' );
  90. /**
  91. *
  92. */
  93. define( 'ONAPP_GETRESOURCE_DEFAULT', 'default' );
  94. /**
  95. *
  96. */
  97. define( 'ONAPP_GETRESOURCE_LOAD', 'load' );
  98. /**
  99. *
  100. */
  101. define( 'ONAPP_GETRESOURCE_LIST', 'list' );
  102. /**
  103. *
  104. *
  105. */
  106. define( 'ONAPP_GETRESOURCE_ADD', 'add' );
  107. /**
  108. *
  109. *
  110. */
  111. define( 'ONAPP_GETRESOURCE_EDIT', 'edit' );
  112. /**
  113. *
  114. *
  115. */
  116. define( 'ONAPP_GETRESOURCE_DELETE', 'delete' );
  117. /**
  118. *
  119. *
  120. */
  121. define( 'ONAPP_GETRESOURCE_VERSION', 'version' );
  122. /**
  123. *
  124. *
  125. */
  126. define( 'ONAPP_ACTIVATE_GETLIST', 'getList' );
  127. /**
  128. *
  129. *
  130. */
  131. define( 'ONAPP_ACTIVATE_LOAD', 'load' );
  132. /**
  133. *
  134. *
  135. */
  136. define( 'ONAPP_ACTIVATE_SAVE', 'save' );
  137. /**
  138. *
  139. *
  140. */
  141. define( 'ONAPP_ACTIVATE_DELETE', 'delete' );
  142. /**
  143. * Specify the GET request
  144. *
  145. */
  146. define( 'ONAPP_REQUEST_METHOD_GET', 'GET' );
  147. /**
  148. * Specify the POST request
  149. *
  150. */
  151. define( 'ONAPP_REQUEST_METHOD_POST', 'POST' );
  152. /**
  153. * Specify the PUT request
  154. *
  155. */
  156. define( 'ONAPP_REQUEST_METHOD_PUT', 'PUT' );
  157. /**
  158. * Specify the DELETE request
  159. *
  160. */
  161. define( 'ONAPP_REQUEST_METHOD_DELETE', 'DELETE' );
  162. /**
  163. * API Wrapper for OnApp
  164. *
  165. *
  166. * @package OnApp
  167. *
  168. *
  169. * @todo Pack using the lib (http://pecl.php.net/)
  170. *
  171. * The wrapper is used to describe the following basic methods: {@link load},
  172. * {@link save}, {@link delete} and {@link getList}.
  173. *
  174. * To create a new class inheriting this one, re-define the
  175. * following variables:
  176. * <code>
  177. *
  178. * // root tag used in the API request
  179. * var $_tagRoot = '<root>';
  180. *
  181. * // alias processing the object data
  182. * var $_resource = '<alias>';
  183. *
  184. * // the fields array used in the response and request to the API server
  185. * var $fields = array(
  186. * ...
  187. * )
  188. * </code>
  189. *
  190. * To create a read-only class, close the save and delete methods.
  191. * To re-define the traditional API aliases to the non-traditional,
  192. * re-define the {@link getResource}, {@link getResourceADD}, {@link getResourceEDIT},
  193. * {@link getResourceLOAD}, {@link getResourceDELETE} and {@link getResourceLIST}
  194. * methods in the class that will be inheriting the ONAPP class.
  195. *
  196. *
  197. * This API provides an interface to onapp.net allowing common virtual machine
  198. * and account management tasks
  199. *
  200. * <b> Usage OnApp_VirtualMachine class example ( Could be applied almost to any of the Wrapper classes ): </b> <br /><br />
  201. * <b> Important ( OnApp CP Permissions Set Up): </b>
  202. * <code>
  203. * Go to OnApp CP.
  204. * Users and Groups -> Roles
  205. * Push pencil edit icon to edit role of the user which you are going to use.
  206. * Check checkbox { View OnApp version (settings.version) }
  207. * Check other permissions in order to perform particular actions.
  208. *</code>
  209. *
  210. * <b>Code example:</b> <br />
  211. *
  212. * Require Wrapper AutoLoad Class:
  213. *
  214. * <code>
  215. * require_once '{Path to the Wrapper}/OnAppInit.php';
  216. * </code>
  217. *
  218. *
  219. * Get OnApp Instance:
  220. *
  221. * <code>
  222. * $onapp = new OnApp_Factory('{IP Address / Hostname}', '{Username}', '{Password}');
  223. * </code>
  224. *
  225. *
  226. * Get OnApp_VirtualMachine Instance:
  227. *
  228. * <code>
  229. * $vm_obj = $onapp->factory('VirtualMachine', {debug mode boolean, not required} );
  230. * </code>
  231. *
  232. *
  233. * Get the list of VMs:
  234. *
  235. * <code>
  236. * $vms = $vm_obj->getList();
  237. * </code>
  238. *
  239. *
  240. * Get particular VM:
  241. *
  242. * <code>
  243. * $vm = $vm_obj->load({VM ID});
  244. * </code>
  245. *
  246. *
  247. * Create a VM:
  248. *
  249. * <code>
  250. * $vm_obj->_label = '{VM Label}';
  251. * $vm_obj->_memory = {VM RAM };
  252. * $vm_obj->_cpu_shares = {VM CPU priority};
  253. * $vm_obj->_hostname = '{Hostname}';
  254. * $vm_obj->_cpus = {number of VM CPUs};
  255. * $vm_obj->_primary_disk_size = {VM Disk Space};
  256. * $vm_obj->_swap_disk_size = {VM Swap Size};
  257. * $vm_obj->_template_id = {VM Template ID};
  258. * $vm_obj->_allowed_hot_migrate = {VM Hot Migrate Boolean Value};
  259. *
  260. * $vm_obj->save();
  261. * </code>
  262. *
  263. *
  264. * Edit VM:
  265. *
  266. * <code>
  267. * $vm_obj->_id = {VM ID};
  268. * $vm_obj->_{Field You Want To Edit} = {New Value};
  269. *
  270. * $vm_obj->save();
  271. * </code>
  272. *
  273. *
  274. * Getting debug log ( depends on debug mode ):
  275. *
  276. * <code>
  277. * print_r( $vm_obj );
  278. * </code>
  279. *
  280. * For full fields reference and curl request details visit: ( http://help.onapp.com/manual.php?m=2 )
  281. */
  282. class OnApp {
  283. /**
  284. * The list of all available options used in the class to create API requests and receive responses,
  285. * as well as to serialize and unserialize.
  286. *
  287. * @access private
  288. * @var array
  289. */
  290. var $_knownOptions = array(
  291. ONAPP_OPTION_CURL_PROXY,
  292. ONAPP_OPTION_CURL_URL,
  293. ONAPP_OPTION_API_TYPE,
  294. ONAPP_OPTION_API_CHARSET,
  295. ONAPP_OPTION_API_CONTENT,
  296. ONAPP_OPTION_DEBUG_MODE
  297. );
  298. /**
  299. * Default options used in the class to create API requests and receive responses,
  300. * as well as serialize and unserialize objects.
  301. *
  302. * @access private
  303. * @var array
  304. */
  305. private $defaultOptions = array(
  306. // cURL proxy
  307. ONAPP_OPTION_CURL_PROXY => '',
  308. // cURL url
  309. ONAPP_OPTION_CURL_URL => '',
  310. // API request and response charset
  311. ONAPP_OPTION_API_CHARSET => 'charset=utf-8',
  312. // API request and response type
  313. ONAPP_OPTION_API_TYPE => 'json',
  314. // API request and response content
  315. ONAPP_OPTION_API_CONTENT => 'application/json',
  316. // Debug mode
  317. ONAPP_OPTION_DEBUG_MODE => false,
  318. );
  319. /**
  320. * The array of the options used to create API requests and receive responses,
  321. * as well as serialize and unserialize objects in the class
  322. *
  323. * By default equals to $_defaultOptions
  324. *
  325. * <code>
  326. * var $options = array(
  327. *
  328. * // cURL proxy
  329. * ONAPP_OPTION_CURL_PROXY => '',
  330. *
  331. * // cURL url
  332. * ONAPP_OPTION_CURL_URL => '',
  333. *
  334. * // API request and response type
  335. * ONAPP_OPTION_API_TYPE => 'xml',
  336. *
  337. * // API request and response charset
  338. * ONAPP_OPTION_API_CHARSET => 'charset=utf-8',
  339. *
  340. * // API request and response content
  341. * ONAPP_OPTION_API_CONTENT => 'application/xml',
  342. *
  343. * // Debug mode
  344. * ONAPP_OPTION_DEBUG_MODE => false
  345. * );
  346. * </code>
  347. *
  348. * @access public
  349. * @var array
  350. */
  351. var $options = array();
  352. /**
  353. * Object cURL
  354. * PHP supports libcurl, a library created by Daniel Stenberg,
  355. * that allows you to connect and communicate to many different types of servers with many different types of protocols.
  356. * libcurl currently supports the http, https, ftp, gopher, telnet, dict, file and ldap protocols.
  357. * libcurl also supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading (this can also be done with PHP's ftp extension),
  358. * HTTP form based upload, proxies, cookies and user+password authentication.
  359. *
  360. * @access private
  361. * @var cURL
  362. */
  363. var $_ch;
  364. /**
  365. * Variable storing the data loaded by the API request. The data is static and cannot be changed by the class setters
  366. *
  367. * @access private
  368. * @var object
  369. */
  370. var $_obj;
  371. /**
  372. * cURL Object alias used as the basic alias to the load, save, delete and getList methods
  373. *
  374. * @access private
  375. * @var string
  376. */
  377. var $_resource = null;
  378. /**
  379. * @access private
  380. * @var string
  381. */
  382. var $_tagRoot = null;
  383. /**
  384. * @access private
  385. * @var array
  386. */
  387. var $_tagRequired = null;
  388. /**
  389. * @access private
  390. * @var boolean
  391. * @todo move in to getter an setter
  392. */
  393. var $_is_auth = false;
  394. /**
  395. * @access private
  396. * @var boolean
  397. * @todo move in to getter an setter
  398. */
  399. var $_is_changed = false;
  400. /**
  401. * @access private
  402. * @var boolean
  403. * @todo move in to getter an setter
  404. */
  405. var $_is_deleted = false;
  406. /**
  407. * Return OnApp version
  408. *
  409. * @access private
  410. * @var sting
  411. */
  412. protected $version;
  413. /**
  414. * Return OnApp release
  415. *
  416. * @access private
  417. * @var sting
  418. */
  419. var $_release;
  420. /**
  421. * Return OnApp fields array mapping
  422. *
  423. * @access private
  424. * @var array
  425. */
  426. protected $fields;
  427. /**
  428. * Holder for storing properties that were setted via magic setter
  429. *
  430. * @var array
  431. * @access protected
  432. */
  433. protected $dynamicFields;
  434. /**
  435. * The Object Logger used to log the processes in the basic and inherited classes
  436. * It is possible to use the debug add error log methods
  437. */
  438. public $logger = null;
  439. /**
  440. * Variable for error handling
  441. *
  442. * @var string
  443. */
  444. protected $errors;
  445. /**
  446. * @var string current class' name
  447. */
  448. protected $className;
  449. /**
  450. *
  451. *
  452. */
  453. protected $response;
  454. /**
  455. * Returns API version
  456. *
  457. * @access private
  458. * @return string $version API version
  459. */
  460. function _apiVersion() {
  461. return $this->version;
  462. }
  463. /**
  464. * Returns Curl Response
  465. *
  466. * @access public
  467. * @return array response
  468. */
  469. function getResponse() {
  470. return $this->response;
  471. }
  472. /**
  473. * Resets all options to default options
  474. *
  475. * @return void
  476. * @access public
  477. */
  478. function resetOptions() {
  479. $this->options = $this->defaultOptions;
  480. }
  481. /**
  482. * Sets an option
  483. *
  484. * Use this method if you do not want
  485. * to set all options in the constructor
  486. *
  487. * @param string $name option name
  488. * @param mixed $value option value
  489. *
  490. * @return void
  491. * @access public
  492. */
  493. function setOption( $name, $value ) {
  494. $this->logger->debug( 'setOption: Set option ' . $name . ' => ' . $value );
  495. $this->options[ $name ] = $value;
  496. }
  497. /**
  498. * Sets several options at once
  499. *
  500. * Use this method if you do not want
  501. * to set all options in the constructor
  502. *
  503. * @param array $options options array
  504. *
  505. * @return void
  506. * @access public
  507. */
  508. function setOptions( array $options ) {
  509. $this->options = array_merge( $this->options, $options );
  510. }
  511. /**
  512. * Returns the URL Alias of the API Class that inherits the OnApp class
  513. *
  514. * Can be redefined if the API does not use the default alias (the alias
  515. * consisting of few fields).
  516. * The following example illustrates:
  517. *
  518. * <code>
  519. * function getResource() {
  520. * return "alias/" . $this->_field_name . "/" . $this->_resource;
  521. * }
  522. * </code>
  523. *
  524. * @param string $action
  525. *
  526. * @return string API resource
  527. */
  528. function getResource( $action = ONAPP_GETRESOURCE_DEFAULT ) {
  529. switch( $action ) {
  530. case ONAPP_GETRESOURCE_LOAD:
  531. case ONAPP_GETRESOURCE_EDIT:
  532. case ONAPP_GETRESOURCE_DELETE:
  533. $resource = $this->getResource() . '/' . $this->_id;
  534. break;
  535. case ONAPP_GETRESOURCE_LIST:
  536. case ONAPP_GETRESOURCE_ADD:
  537. $resource = $this->getResource();
  538. break;
  539. case ONAPP_GETRESOURCE_DEFAULT:
  540. default:
  541. $resource = $this->_resource;
  542. }
  543. $this->logger->debug( 'getResource( ' . $action . ' ): return ' . $resource );
  544. return $resource;
  545. }
  546. /**
  547. * Returns true if the API instance has authentication information set and authentication was succesful
  548. *
  549. * @return boolean true if authenticated
  550. * @access public
  551. *
  552. * @todo move to the defaut getter
  553. */
  554. function isAuthenticate() {
  555. return $this->_is_auth;
  556. }
  557. /**
  558. * Returns true if the Object was changed and API response was succesfull
  559. *
  560. * @return boolean true if the Object was changed
  561. * @access public
  562. *
  563. * @todo move to the defaut getter
  564. */
  565. function isChanged() {
  566. return $this->_is_changed;
  567. }
  568. /**
  569. * Returns true if the Object was deleted in the API instance
  570. * and API response was succesfull
  571. *
  572. * @return boolean true if the Object was deleted
  573. * @access public
  574. *
  575. * @todo move to the defaut getter
  576. */
  577. function isDelete() {
  578. return $this->_is_deleted;
  579. }
  580. /**
  581. * Returns Text written to the full class logs
  582. *
  583. * When the log level is set to debug, the debug messages will be also
  584. * included
  585. *
  586. * @return string All formatted logs
  587. * @access public
  588. */
  589. function logs() {
  590. if( isset( $this->logger ) ) {
  591. return $this->logger->logs();
  592. }
  593. }
  594. /**
  595. * Authorizes users in the system by the specified URL by means of cURL
  596. *
  597. * To authorize, set the user name and password. Specify the Proxy, if
  598. * needed. When authorized, {@link load}, {@link save}, {@link delete} and
  599. * {@link getList} methods can be used.
  600. *
  601. * @param string $url API URL
  602. * @param string $user user name
  603. * @param string $pass password
  604. * @param string $proxy (optional) proxy server
  605. *
  606. * @return void
  607. * @access public
  608. */
  609. function auth( $url, $user, $pass, $proxy = '' ) {
  610. $this->logger->setDebug( $this->options[ ONAPP_OPTION_DEBUG_MODE ] );
  611. $this->logger->setTimezone();
  612. $this->logger->debug( 'auth: Authorization(url => ' . $url . ', user => ' . $user . ', pass => ********).' );
  613. $this->setOption( ONAPP_OPTION_CURL_URL, $url );
  614. $this->setOption( ONAPP_OPTION_CURL_PROXY, $proxy );
  615. $this->_init_curl( $user, $pass );
  616. $this->setAPIResource( ONAPP_GETRESOURCE_VERSION );
  617. $response = $this->sendRequest( ONAPP_REQUEST_METHOD_GET );
  618. if( $response[ 'info' ][ 'http_code' ] == '200' ) {
  619. $this->setAPIVersion( $response[ 'response_body' ] );
  620. if( $this->getClassName() != 'OnApp' ) {
  621. $this->initFields( $this->version );
  622. }
  623. $this->setErrors();
  624. $this->_is_auth = true;
  625. }
  626. else {
  627. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  628. case 'xml':
  629. case 'json':
  630. $tag = 'version';
  631. $this->version = null;
  632. $objCast = new OnApp_Helper_Caster( $this );
  633. $error = $objCast->unserialize( $this->getClassName(), $response[ 'response_body' ], null, 'errors' );
  634. break;
  635. default:
  636. //todo add CLI check
  637. $msg = 'FATAL ERROR: Caster for "' . $this->options[ ONAPP_OPTION_API_TYPE ] . '" is not defined'
  638. . ' in FILE ' . __FILE__ . ' LINE ' . __LINE__ . PHP_EOL . PHP_EOL;
  639. try {
  640. throw new Exception( $msg );
  641. }
  642. catch( Exception $e ) {
  643. echo $e->getMessage();
  644. exit( $this->logger->logs() );
  645. }
  646. }
  647. $this->setErrors( $error );
  648. $this->_is_auth = false;
  649. }
  650. }
  651. protected function setAPIVersion( $data ) {
  652. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  653. case 'xml':
  654. case 'json':
  655. $tag = 'version';
  656. $this->version = null;
  657. $objCast = new OnApp_Helper_Caster( $this );
  658. $this->version = $objCast->unserialize( $this->getClassName(), $data, null, $tag );
  659. break;
  660. default:
  661. //todo add CLI check
  662. $msg = 'FATAL ERROR: Caster for "' . $this->options[ ONAPP_OPTION_API_TYPE ] . '" is not defined'
  663. . ' in FILE ' . __FILE__ . ' LINE ' . __LINE__ . PHP_EOL . PHP_EOL;
  664. try {
  665. throw new Exception( $msg );
  666. }
  667. catch( Exception $e ) {
  668. echo $e->getMessage();
  669. exit( $this->logger->logs() );
  670. }
  671. }
  672. $this->version = (float)$this->version;
  673. }
  674. public function initFields( $version = null, $className = '' ) {
  675. if( ! is_null( $version ) ) {
  676. $this->version = $version;
  677. }
  678. if( is_null( $this->fields ) && ( $this->getClassName() != 'OnApp' ) ) {
  679. $this->logger->debug( 'No fields defined for current API version [ ' . $version . ' ]' );
  680. // if( IS_CLI ) {
  681. // throw new Exception( 'No fields defined for current API version [ ' . $version . ' ]' );
  682. // }
  683. // else {
  684. // $this->logger->error( 'No fields defined for current API version [ ' . $version . ' ]' );
  685. // }
  686. }
  687. elseif( ! is_null( $version ) ) {
  688. if( $version == $this->version ) {
  689. if( $this->defaultOptions[ ONAPP_OPTION_DEBUG_MODE ] ) {
  690. $this->logger->debug( $className . '::initFields, version ' . $version . PHP_EOL . print_r( $this->fields, true ) );
  691. }
  692. else {
  693. $this->logger->add( $className . '::initFields, version ' . $version );
  694. }
  695. }
  696. }
  697. if( is_null( $this->fields ) && get_called_class() != 'OnApp' ) {
  698. throw new Exception( sprintf(
  699. "The wrapper class '%s' does not support OnApp version '%s'",
  700. get_called_class(),
  701. $version
  702. ) );
  703. }
  704. }
  705. /**
  706. * Sets an option for a cURL transfer
  707. *
  708. * @param string $user user name
  709. * @param string $pass password
  710. * @param string $cookiedir Cookies directory
  711. *
  712. * @return void
  713. * @access private
  714. *
  715. * @todo check response from basic URL
  716. */
  717. function _init_curl( $user, $pass, $cookiedir = '' ) {
  718. $this->logger->debug( "_init_curl: Init Curl (cookiedir => '$cookiedir')." );
  719. $this->_ch = curl_init();
  720. //todo ???
  721. //$this->_is_auth = true;
  722. if( strlen( $this->options[ ONAPP_OPTION_CURL_PROXY ] ) > 0 ) {
  723. curl_setopt(
  724. $this->_ch,
  725. CURLOPT_PROXY,
  726. $this->options[ ONAPP_OPTION_CURL_PROXY ]
  727. );
  728. }
  729. curl_setopt( $this->_ch, CURLOPT_SSL_VERIFYPEER, false );
  730. curl_setopt( $this->_ch, CURLOPT_RETURNTRANSFER, true );
  731. curl_setopt(
  732. $this->_ch, CURLOPT_USERPWD,
  733. $user . ':' . $pass
  734. );
  735. }
  736. /**
  737. * Closes a cURL session
  738. *
  739. * @return void
  740. * @access public
  741. */
  742. function close_curl() {
  743. curl_close( $this->_ch );
  744. }
  745. /**
  746. * Sets full API path to the variable cURL
  747. *
  748. * @param string $resource API alias
  749. * @param boolean $append_api_version
  750. * @param string $queryString API request
  751. *
  752. * @return void
  753. * @access public
  754. */
  755. function setAPIResource( $resource, $append_api_version = true, $queryString = '' ) {
  756. $url = $this->options[ ONAPP_OPTION_CURL_URL ];
  757. $this->logger->add(
  758. 'setAPIResource: Set an option for a cURL transfer (' .
  759. ' url => "' . $url . '", ' .
  760. ' resource => "' . $resource . '", ' .
  761. ' data_type => "' . $this->options[ ONAPP_OPTION_API_TYPE ] . '"' .
  762. ' append_api_version => ' . $this->getAPIVersion() . ',' .
  763. ' queryString => "' . $queryString . '" ).'
  764. );
  765. if( $append_api_version ) {
  766. curl_setopt(
  767. $this->_ch,
  768. CURLOPT_URL,
  769. sprintf(
  770. '%1$s/%2$s.%3$s?%4$s',
  771. $url,
  772. $resource,
  773. $this->options[ ONAPP_OPTION_API_TYPE ],
  774. $queryString )
  775. );
  776. }
  777. else {
  778. curl_setopt(
  779. $this->_ch,
  780. CURLOPT_URL,
  781. sprintf(
  782. '%1$s/%2$s?%3$s',
  783. $url,
  784. $resource,
  785. $queryString
  786. )
  787. );
  788. }
  789. }
  790. /**
  791. * Sends API request to the API server and gets response from it
  792. *
  793. * @param string $method
  794. * @param array|null $data
  795. *
  796. * @return array|bool cURL response
  797. */
  798. protected function sendRequest( $method, $data = null ) {
  799. $alowed_methods = array(
  800. ONAPP_REQUEST_METHOD_GET,
  801. ONAPP_REQUEST_METHOD_POST,
  802. ONAPP_REQUEST_METHOD_PUT,
  803. ONAPP_REQUEST_METHOD_DELETE,
  804. );
  805. if( ! in_array( $method, $alowed_methods ) ) {
  806. $this->logger->error( 'Wrong request method.' );
  807. }
  808. $debug_msg = 'Send ' . $method . ' request.';
  809. if( $data ) {
  810. $debug_msg .= ' Request:' . PHP_EOL . print_r( $data, true );
  811. }
  812. $this->logger->debug( $debug_msg );
  813. $http_header = array(
  814. 'Content-Type: ' . $this->options[ ONAPP_OPTION_API_CONTENT ],
  815. 'Accept: ' . $this->options[ ONAPP_OPTION_API_CONTENT ]
  816. );
  817. curl_setopt( $this->_ch, CURLOPT_CUSTOMREQUEST, $method );
  818. switch( $method ) {
  819. case ONAPP_REQUEST_METHOD_GET:
  820. curl_setopt( $this->_ch, CURLOPT_HTTPGET, true );
  821. if( ! is_null( $data ) ) {
  822. curl_setopt( $this->_ch, CURLOPT_POSTFIELDS, $data );
  823. }
  824. else {
  825. $http_header[ ] = 'Content-Length: 0';
  826. }
  827. break;
  828. case ONAPP_REQUEST_METHOD_POST:
  829. if( ! is_null( $data ) ) {
  830. curl_setopt( $this->_ch, CURLOPT_POSTFIELDS, $data );
  831. }
  832. break;
  833. case ONAPP_REQUEST_METHOD_PUT:
  834. $http_header[ ] = 'Content-Length: ' . strlen( $data );
  835. if( ! is_null( $data ) ) {
  836. curl_setopt( $this->_ch, CURLOPT_POSTFIELDS, $data );
  837. }
  838. break;
  839. case ONAPP_REQUEST_METHOD_DELETE:
  840. if( ! is_null( $data ) ) {
  841. $http_header[ ] = 'Content-Length: ' . strlen( $data );
  842. curl_setopt( $this->_ch, CURLOPT_POSTFIELDS, $data );
  843. }
  844. break;
  845. }
  846. curl_setopt( $this->_ch, CURLOPT_RETURNTRANSFER, true );
  847. curl_setopt( $this->_ch, CURLOPT_HEADER, true );
  848. curl_setopt( $this->_ch, CURLOPT_HTTPHEADER, $http_header );
  849. $result = array();
  850. $result[ 'response_body' ] = curl_exec( $this->_ch );
  851. $result[ 'info' ] = curl_getinfo( $this->_ch );
  852. $curlHeaderSize = $result[ 'info' ][ 'header_size' ];
  853. $result[ 'headers' ] = mb_substr( $result[ 'response_body' ], 0, $curlHeaderSize );
  854. $result[ 'response_body' ] = mb_substr( $result[ 'response_body' ], $curlHeaderSize );
  855. if( ! $result[ 'response_body' ] && $method == ONAPP_REQUEST_METHOD_DELETE ||
  856. ! $result[ 'response_body' ] && $method == ONAPP_REQUEST_METHOD_PUT
  857. ) {
  858. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  859. case 'json':
  860. $result[ 'response_body' ] = '{}';
  861. break;
  862. case 'xml':
  863. $result[ 'response_body' ] = ' ';
  864. break;
  865. default:
  866. $this->logger->error( 'Unsupported API method ' . $this->options[ ONAPP_OPTION_API_TYPE ] );
  867. break;
  868. }
  869. }
  870. $this->logger->debug( 'Receive Response ' . print_r( $result, true ) );
  871. if( ! $result[ 'response_body' ] ) {
  872. $this->logger->debug( 'Response body is empty for method: ' . $method );
  873. return false;
  874. }
  875. $this->response = $result;
  876. $content_type = $result[ 'info' ][ 'content_type' ];
  877. if( $content_type == $this->options[ ONAPP_OPTION_API_CONTENT ] . "; " . $this->options[ ONAPP_OPTION_API_CHARSET ] ) {
  878. switch( $result[ 'info' ][ 'http_code' ] ) {
  879. case 200:
  880. case 201:
  881. case 204:
  882. break;
  883. case 422:
  884. case 404:
  885. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  886. case 'xml':
  887. case 'json':
  888. $this->logger->add( 'Response (code => ' . $result[ 'info' ][ 'http_code' ] . ', cast:' . PHP_EOL . $result[ 'response_body' ] );
  889. break;
  890. }
  891. break;
  892. default:
  893. $this->logger->warning( 'Response (code => ' . $result[ 'info' ][ 'http_code' ] . ', body: ' . PHP_EOL . $result[ 'response_body' ] );
  894. $result[ 'errors' ] = $result[ 'response_body' ];
  895. }
  896. }
  897. else {
  898. $this->logger->add( 'sendRequest: Response:' . PHP_EOL . $result[ 'response_body' ] );
  899. $result[ 'errors' ] = 'Bad response content type: ' . $content_type;
  900. $result[ 'error_response' ] = $result[ 'response_body' ];
  901. }
  902. $this->_errno_curl( $result[ 'response_body' ] );
  903. return $result;
  904. }
  905. /**
  906. *
  907. * @param type $label
  908. *
  909. * @return string
  910. */
  911. public function getHeader( $label = null ) {
  912. if( ! $label ) {
  913. return $this->response[ 'headers' ];
  914. }
  915. $content = '';
  916. preg_match_all( '|' . $label . ': (.*)|', $this->response[ 'headers' ], $content );
  917. return implode( '', $content[ 1 ] );
  918. }
  919. /**
  920. * The method validates the API request errors
  921. *
  922. * You will get an error in case of the following error codes:
  923. * - UNSUPPORTED PROTOCOL
  924. * - FAILED INIT
  925. * - URL MALFORMAT
  926. * - COULDNT RESOLVE PROXY
  927. * - COULDNT RESOLVE HOST
  928. *
  929. * @param string $response_body API Response body
  930. *
  931. * @return void
  932. * @access private
  933. */
  934. function _errno_curl( $response_body ) {
  935. $error_no = curl_errno( $this->_ch );
  936. switch( $error_no ) {
  937. case CURLE_OK:
  938. // Note: the 0 code does not mean an error, but it means success
  939. $this->logger->debug( 'Response Body: OK.' . PHP_EOL . $response_body );
  940. break;
  941. case CURLE_UNSUPPORTED_PROTOCOL : // 1
  942. case CURLE_UNSUPPORTED_PROTOCOL: // 2
  943. case CURLE_FAILED_INIT: // 3
  944. case CURLE_URL_MALFORMAT: // 4
  945. case CURLE_URL_MALFORMAT_USER: // 5
  946. case CURLE_COULDNT_RESOLVE_PROXY: // 6
  947. case CURLE_COULDNT_RESOLVE_HOST: // 7
  948. $this->logger->warning(
  949. 'Response Body: Error #' . $error_no,
  950. __FILE__,
  951. __LINE__
  952. );
  953. break;
  954. default:
  955. $this->logger->warning( 'sendRequest: unknown error number ' . $error_no );
  956. }
  957. }
  958. /**
  959. * Casts an API response to the Array of Objects or an Object
  960. *
  961. * @param array $response API response
  962. *
  963. * @return mixed (Array of Object or Object)
  964. */
  965. protected function _castResponseToClass( $response ) {
  966. $this->logger->debug( '_castResponseToClass: Cast response in to Object.' );
  967. if( isset( $response[ 'response_body' ] ) ) {
  968. $http_code = $response[ 'info' ][ 'http_code' ];
  969. switch( $http_code ) {
  970. case 200:
  971. case 201:
  972. case 404:
  973. case 422:
  974. case 204:
  975. return $this->castStringToClass( $response );
  976. break;
  977. case 500:
  978. $this->setErrors( 'We\'re sorry, but something went wrong.' );
  979. return $this;
  980. default:
  981. $this->setErrors( 'Bad response ( code => ' . $http_code . ', response => ' . $response[ 'response_body' ] . ' )' );
  982. }
  983. }
  984. else {
  985. $this->logger->error(
  986. 'castResponseToClass: Can\'t parse ' . $response[ 'response_body' ],
  987. __FILE__,
  988. __LINE__
  989. );
  990. }
  991. }
  992. /**
  993. * Casts string (API response body content) to the Object
  994. *
  995. * @param array $content class string content
  996. *
  997. * @return mixed array of Objects or Object
  998. */
  999. protected function castStringToClass( array $content ) {
  1000. $className = $this->getClassName();
  1001. $tagMap = $this->fields;
  1002. $this->logger->add( 'castStringToClass: cast data into the ' . $className . ' object.' );
  1003. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  1004. case 'xml':
  1005. case 'json':
  1006. $root = $this->_tagRoot;
  1007. $data = $content[ 'response_body' ];
  1008. $objCast = new OnApp_Helper_Caster( $this );
  1009. if( $content[ 'info' ][ 'http_code' ] > 201 ) {
  1010. $root = 'errors';
  1011. $errors = $objCast->unserialize( $className, $data, $tagMap, $root );
  1012. $this->setErrors( $errors );
  1013. //todo ????
  1014. //if( empty( $this->errors ) && isset( $content[ 'error_response' ] ) ) {
  1015. // $this->setErrors( $content[ 'error_response' ] );
  1016. //}
  1017. return $this;
  1018. }
  1019. else {
  1020. return $objCast->unserialize( $className, $data, $tagMap, $root );
  1021. }
  1022. default:
  1023. $msg = 'FATAL ERROR: Caster for "' . $this->options[ ONAPP_OPTION_API_TYPE ] . '" is not defined'
  1024. . ' in FILE ' . __FILE__ . ' LINE ' . __LINE__ . PHP_EOL . PHP_EOL;
  1025. try {
  1026. throw new Exception( $msg );
  1027. }
  1028. catch( Exception $e ) {
  1029. echo $e->getMessage();
  1030. //todo ???
  1031. exit( $this->logger->logs() );
  1032. }
  1033. }
  1034. }
  1035. /**
  1036. * Activates action performed with object
  1037. *
  1038. * @param string $action_name the name of action
  1039. *
  1040. * @access public
  1041. */
  1042. function activate( $action_name ) {
  1043. }
  1044. /**
  1045. * Sends an API request to get the Objects. After requesting,
  1046. * unserializes the received response into the array of Objects
  1047. *
  1048. * @param mixed $params
  1049. * @param mixed $url_args
  1050. *
  1051. * @return array|bool the array of Object instances
  1052. */
  1053. public function getList( $params = null, $url_args = null ) {
  1054. $this->activate( ONAPP_ACTIVATE_GETLIST );
  1055. $this->logger->add( 'Run ' . __METHOD__ );
  1056. $result = $this->sendGet( ONAPP_GETRESOURCE_LIST, $params, $url_args );
  1057. if( ! is_null( $this->getErrorsAsArray() ) ) {
  1058. return false;
  1059. }
  1060. else {
  1061. if( ! is_array( $result ) && ! is_null( $result ) ) {
  1062. $result = array( $result );
  1063. }
  1064. return $result;
  1065. }
  1066. }
  1067. /**
  1068. * Sends an API request to get the Object after sending,
  1069. * unserializes the response into an object
  1070. *
  1071. * The key field Parameter ID is used to load the Object. You can re-set
  1072. * this parameter in the class inheriting OnApp class.
  1073. *
  1074. * @param integer $id Object id
  1075. *
  1076. * @return mixed serialized Object instance from API
  1077. * @access public
  1078. */
  1079. function load( $id = null ) {
  1080. $this->activate( ONAPP_ACTIVATE_LOAD );
  1081. if( is_null( $id ) && ! is_null( $this->_id ) ) {
  1082. $id = $this->_id;
  1083. }
  1084. if( is_null( $id ) &&
  1085. isset( $this->_obj ) &&
  1086. ! is_null( $this->_obj->_id )
  1087. ) {
  1088. $id = $this->_obj->_id;
  1089. }
  1090. if( is_null( $id ) ) {
  1091. $this->logger->error(
  1092. 'load: Can\'t set variable ' . $id,
  1093. __FILE__,
  1094. __LINE__
  1095. );
  1096. }
  1097. $this->logger->add( 'load: Load class ( id => ' . $id . ' ).' );
  1098. if( strlen( $id ) > 0 ) {
  1099. $this->_id = $id;
  1100. $this->setAPIResource( $this->getResource( ONAPP_GETRESOURCE_LOAD ) );
  1101. $response = $this->sendRequest( ONAPP_REQUEST_METHOD_GET );
  1102. $result = $this->castStringToClass( $response );
  1103. $this->_obj = $result;
  1104. $this->_id = $this->_obj->_id;
  1105. return $result;
  1106. }
  1107. else {
  1108. $this->logger->error(
  1109. 'load: argument id not set.',
  1110. __FILE__,
  1111. __LINE__
  1112. );
  1113. }
  1114. }
  1115. /**
  1116. * The method saves an Object to your account
  1117. *
  1118. * After sending an API request to create an object or change the data in
  1119. * the existing object, the method checks the response and loads the
  1120. * exisitng object with the new data.
  1121. *
  1122. * This method can be closed for read only objects of the inherited class
  1123. * <code>
  1124. * function save() {
  1125. * $this->logger->error(
  1126. * "Call to undefined method ".__CLASS__."::save()",
  1127. * __FILE__,
  1128. * __LINE__
  1129. * );
  1130. * }
  1131. * </code>
  1132. *
  1133. * @return void
  1134. * @access public
  1135. */
  1136. function save() {
  1137. $this->activate( ONAPP_ACTIVATE_SAVE );
  1138. if( is_null( $this->_id ) ) {
  1139. $obj = $this->_create();
  1140. }
  1141. else {
  1142. $obj = $this->_edit();
  1143. }
  1144. //todo handle errors
  1145. if( isset( $obj ) && ! isset( $obj->errors ) ) {
  1146. $this->load();
  1147. }
  1148. }
  1149. /**
  1150. * The method creates a new Object
  1151. *
  1152. * @return object Serialized API Response
  1153. * @access private
  1154. */
  1155. function _create() {
  1156. $this->logger->add( 'Create new Object.' );
  1157. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  1158. case 'xml':
  1159. case 'json':
  1160. $objCast = new OnApp_Helper_Caster( $this );
  1161. $data = $objCast->serialize( $this->_tagRoot, $this->getFieldsToSend() );
  1162. $this->logger->debug( 'serialize: serialized data:' . PHP_EOL . $data );
  1163. $this->setAPIResource( $this->getResource( ONAPP_GETRESOURCE_ADD ) );
  1164. $response = $this->sendRequest( ONAPP_REQUEST_METHOD_POST, $data );
  1165. $result = $this->_castResponseToClass( $response );
  1166. $this->_obj = $result;
  1167. break;
  1168. default:
  1169. $msg = 'FATAL ERROR: Caster for "' . $this->options[ ONAPP_OPTION_API_TYPE ] . '" is not defined'
  1170. . ' in FILE ' . __FILE__ . ' LINE ' . __LINE__ . PHP_EOL . PHP_EOL;
  1171. try {
  1172. throw new Exception( $msg );
  1173. }
  1174. catch( Exception $e ) {
  1175. echo $e->getMessage();
  1176. //todo ???
  1177. exit( $this->logger->logs() );
  1178. }
  1179. }
  1180. return $result;
  1181. }
  1182. /**
  1183. * The method edits an existing Object
  1184. *
  1185. * @return object Serialized API Response
  1186. * @access private
  1187. */
  1188. function _edit() {
  1189. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  1190. case 'xml':
  1191. case 'json':
  1192. $objCast = new OnApp_Helper_Caster( $this );
  1193. $data = $objCast->serialize( $this->_tagRoot, $this->getFieldsToSend() );
  1194. $this->logger->debug( 'serialize: serialized data:' . PHP_EOL . $data );
  1195. $this->setAPIResource( $this->getResource( ONAPP_GETRESOURCE_EDIT ) );
  1196. $response = $this->sendRequest( ONAPP_REQUEST_METHOD_PUT, $data );
  1197. if( $response[ 'info' ][ 'http_code' ] > 201 ) {
  1198. $this->_castResponseToClass( $response );
  1199. }
  1200. else {
  1201. $this->load( $this->_id );
  1202. }
  1203. break;
  1204. default:
  1205. $msg = 'FATAL ERROR: Caster for "' . $this->options[ ONAPP_OPTION_API_TYPE ] . '" is not defined'
  1206. . ' in FILE ' . __FILE__ . ' LINE ' . __LINE__ . PHP_EOL . PHP_EOL;
  1207. try {
  1208. throw new Exception( $msg );
  1209. }
  1210. catch( Exception $e ) {
  1211. echo $e->getMessage();
  1212. //todo ???
  1213. exit( $this->logger->logs() );
  1214. }
  1215. }
  1216. }
  1217. /**
  1218. * Creates data fro API response to save or change the object data
  1219. *
  1220. * Returns the Hash of Object fields with values
  1221. *
  1222. * @return hash of string
  1223. * @access private
  1224. */
  1225. protected function getFieldsToSend() {
  1226. $this->logger->debug( 'getFieldsToSend: Prepare data array:' );
  1227. $result = array();
  1228. foreach( $this->fields as $key => $value ) {
  1229. //skip property from request
  1230. if( isset( $value[ ONAPP_FIELD_SKIP_FROM_REQUEST ] ) && $value[ ONAPP_FIELD_SKIP_FROM_REQUEST ] ) {
  1231. //todo add log record
  1232. continue;
  1233. }
  1234. $property = $value[ ONAPP_FIELD_MAP ];
  1235. if( isset( $value[ ONAPP_FIELD_REQUIRED ] ) && $value[ ONAPP_FIELD_REQUIRED ] ) {
  1236. if( isset( $this->$property ) && ! empty( $this->$property ) ) {
  1237. $result[ $key ] = $this->$property;
  1238. }
  1239. elseif( isset( $this->$property ) && is_bool( $this->$property ) ) {
  1240. $result[ $key ] = $this->$property;
  1241. }
  1242. elseif( isset( $this->_obj->$property ) ) {
  1243. $result[ $key ] = $this->_obj->$property;
  1244. }
  1245. elseif( isset( $value[ ONAPP_FIELD_DEFAULT_VALUE ] ) ) {
  1246. $result[ $key ] = $value[ ONAPP_FIELD_DEFAULT_VALUE ];
  1247. }
  1248. else {
  1249. $this->logger->error(
  1250. 'getFieldsToSent: Property ' . $property . ' not defined',
  1251. __FILE__,
  1252. __LINE__
  1253. );
  1254. }
  1255. }
  1256. elseif( isset( $this->$property ) ) {
  1257. $result[ $key ] = $this->$property;
  1258. }
  1259. else {
  1260. if( isset( $this->_obj->$property ) ) {
  1261. $result[ $key ] = $this->_obj->$property;
  1262. }
  1263. elseif( isset( $value[ ONAPP_FIELD_DEFAULT_VALUE ] ) ) {
  1264. $result[ $key ] = $value[ ONAPP_FIELD_DEFAULT_VALUE ];
  1265. }
  1266. }
  1267. if( isset( $result[ $key ] ) ) {
  1268. $this->logger->debug( 'getFieldsToSent: set attribute ( ' . $key . ' => ' . print_r( $result[ $key ], true ) . ' ).' );
  1269. }
  1270. }
  1271. return $result;
  1272. }
  1273. /**
  1274. * Sends an API request to delete an Object from your account
  1275. *
  1276. * This method can be closed for read only objects of the inherited class
  1277. * <code>
  1278. * function delete() {
  1279. * $this->logger->error(
  1280. * "Call to undefined method ".__CLASS__."::delete()",
  1281. * __FILE__,
  1282. * __LINE__
  1283. * );
  1284. * }
  1285. * </code>
  1286. *
  1287. * @return boolean the Object deleted
  1288. * @access public
  1289. */
  1290. function delete() {
  1291. $this->activate( ONAPP_ACTIVATE_DELETE );
  1292. $this->logger->add( 'Delete existing Object ( id => ' . $this->_id . ' ).' );
  1293. $this->sendDelete( ONAPP_GETRESOURCE_DELETE );
  1294. if( count( $this->getErrorsAsArray() ) < 1 ) {
  1295. $this->_is_deleted = true;
  1296. }
  1297. }
  1298. function sendPost( $resource, $data = null ) {
  1299. return $this->_action( ONAPP_REQUEST_METHOD_POST, $resource, $data );
  1300. }
  1301. protected function sendGet( $resource, $data = null, $url_args = null ) {
  1302. return $this->_action( ONAPP_REQUEST_METHOD_GET, $resource, $data, $url_args );
  1303. }
  1304. function sendPut( $resource, $data = null ) {
  1305. return $this->_action( ONAPP_REQUEST_METHOD_PUT, $resource, $data );
  1306. }
  1307. function sendDelete( $resource, $data = null ) {
  1308. return $this->_action( ONAPP_REQUEST_METHOD_DELETE, $resource, $data );
  1309. }
  1310. /**
  1311. * Sends API Requests to realize not base actions
  1312. *
  1313. * @param string $method
  1314. * @param string $resource
  1315. * @param array|null $data
  1316. *
  1317. * @return bool|mixed (Array of Object or Object)
  1318. */
  1319. protected function _action( $method, $resource, $data = null, $url_args = null ) {
  1320. switch( $this->options[ ONAPP_OPTION_API_TYPE ] ) {
  1321. case 'xml':
  1322. case 'json':
  1323. if( ! is_null( $data ) ) {
  1324. $objCast = new OnApp_Helper_Caster( $this );
  1325. $data = $objCast->serialize( $data[ 'root' ], $data[ 'data' ] );
  1326. $this->logger->debug( 'Additional parameters: ' . $data );
  1327. }
  1328. $url_args = ( $url_args ) ? preg_replace( '/%5B(0-9){1,4}%5D/', '%5B%5D', http_build_query( $url_args ) ) : '';
  1329. $this->setAPIResource( $this->getResource( $resource ), true, $url_args );
  1330. $response = $this->sendRequest( $method, $data );
  1331. $result = $this->_castResponseToClass( $response );
  1332. if( $response[ 'info' ][ 'http_code' ] > 400 ) {
  1333. if( is_null( $result ) ) {
  1334. $this->_obj = clone $this;
  1335. }
  1336. else {
  1337. $this->_obj->errors = $result->getErrorsAsArray();
  1338. }
  1339. return false;
  1340. }
  1341. else {
  1342. $this->_obj = $result;
  1343. }
  1344. break;
  1345. default:
  1346. $this->logger->error( '_action: Can\'t find serialize and unserialize functions for type (apiVersion => \'' . $this->getAPIVersion() . "').", __FILE__, __LINE__ );
  1347. break;
  1348. }
  1349. return $result;
  1350. }
  1351. public function getClassName() {
  1352. if( is_null( $this->className ) ) {
  1353. return __CLASS__;
  1354. }
  1355. else {
  1356. return $this->className;
  1357. }
  1358. }
  1359. public function getClassFields() {
  1360. return $this->fields;
  1361. }
  1362. public function getAPIVersion() {
  1363. return $this->version;
  1364. }
  1365. /**
  1366. * Store errors
  1367. *
  1368. * @param mixed $errors
  1369. *
  1370. * @return void
  1371. */
  1372. public function setErrors( $errors = null ) {
  1373. if( is_null( $errors ) ) {
  1374. $this->errors = null;
  1375. }
  1376. else {
  1377. $this->errors = (array)$errors;
  1378. }
  1379. }
  1380. /**
  1381. * Return errors as string
  1382. *
  1383. * @param string $glue
  1384. *
  1385. * @return string
  1386. */
  1387. public function getErrorsAsString( $glue = '<br />' ) {
  1388. $errors = '';
  1389. foreach( $this->errors as $key => $value ) {
  1390. if( is_array( $value ) ) {
  1391. foreach( $value as $k => $v ) {
  1392. $errors .= $key . ': ' . $v . $glue;
  1393. }
  1394. }
  1395. else {
  1396. $errors .= $value . $glue;
  1397. }
  1398. }
  1399. $errors = substr( $errors, 0, - strlen( $glue ) );
  1400. return $errors;
  1401. }
  1402. /**
  1403. * Return errors as array
  1404. *
  1405. * @return array
  1406. */
  1407. public function getErrorsAsArray() {
  1408. return $this->errors;
  1409. }
  1410. /**
  1411. * Unset unnecessary fields
  1412. *
  1413. * @param array $fields fields name
  1414. *
  1415. * @return void
  1416. */
  1417. public function unsetFields( $fields ) {
  1418. foreach( $fields as $field ) {
  1419. unset( $this->fields[ $field ] );
  1420. }
  1421. }
  1422. // getters, setters & other magic stuff //
  1423. public function __construct() {
  1424. $this->options = $this->defaultOptions;
  1425. $this->logger = new OnApp_Helper_Logger;
  1426. }
  1427. /**
  1428. * Standard method to handle getting non-existent class' property
  1429. *
  1430. * @param string $name property name
  1431. *
  1432. * @return mixed
  1433. */
  1434. public function __get( $name ) {
  1435. // legacy getting errors
  1436. // remove after rewriting the code to use getErrors() method
  1437. // instead of direct access
  1438. switch( $name ) {
  1439. case 'error':
  1440. return $this->getErrorsAsArray();
  1441. break;
  1442. case '_version':
  1443. return $this->getAPIVersion();
  1444. break;
  1445. }
  1446. if( ! isset( $this->dynamicFields[ $name ] ) ) {
  1447. return null;
  1448. }
  1449. if( is_object( $this->dynamicFields[ $name ] ) ) {
  1450. if( get_class( $this->dynamicFields[ $name ] ) == 'DataHolder' ) {
  1451. $this->dynamicFields[ $name ] = OnApp_Helper_Caster::unserializeNested( $this->dynamicFields[ $name ] );
  1452. }
  1453. }
  1454. return $this->dynamicFields[ $name ];
  1455. }
  1456. /**
  1457. * Standard method to handle writing into non-existent class' property
  1458. *
  1459. * @param string $name property name
  1460. * @param string $value property value
  1461. *
  1462. * @return void
  1463. */
  1464. public function __set( $name, $value ) {
  1465. $this->dynamicFields[ $name ] = $value;
  1466. }
  1467. /**
  1468. * Standard method to check if property was set via setter
  1469. *
  1470. * @param string $name property name
  1471. *
  1472. * @return bool result of checking property
  1473. */
  1474. public function __isset( $name ) {
  1475. // legacy getting errors
  1476. // remove after rewriting the code to use getErrors() method
  1477. // instead of direct access
  1478. switch( $name ) {
  1479. case 'error':
  1480. return isset( $this->errors );
  1481. break;
  1482. case '_version':
  1483. return isset( $this->version );
  1484. break;
  1485. }
  1486. return isset( $this->dynamicFields[ $name ] );
  1487. }
  1488. /**
  1489. * Standard method to unset property which was set via setter
  1490. *
  1491. * @param string $name property name
  1492. *
  1493. * @return void
  1494. */
  1495. public function __unset( $name ) {
  1496. unset( $this->dynamicFields[ $name ] );
  1497. }
  1498. }