Overview

Namespaces

  • NGS
    • Client
      • Exception
    • Converter
    • Patterns
  • PHP

Classes

  • ApplicationProxy
  • CrudProxy
  • DomainProxy
  • HttpRequest
  • QueryString
  • ReportingProxy
  • RestHttp
  • StandardProxy
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: namespace NGS\Client;
  3: 
  4: require_once(__DIR__.'/../Utils.php');
  5: require_once(__DIR__.'/../Name.php');
  6: require_once(__DIR__.'/RestHttp.php');
  7: require_once(__DIR__.'/../Patterns/Repository.php');
  8: require_once(__DIR__.'/QueryString.php');
  9: 
 10: use InvalidArgumentException;
 11: use NGS\Converter\ObjectConverter;
 12: use NGS\Name;
 13: use NGS\Patterns\Repository;
 14: use NGS\Utils;
 15: 
 16: /**
 17:  * Proxy service to various domain operations such as bulk persistence,
 18:  * data analysis, and remote service calls counting and event sourcing.
 19:  * It is preferred to use domain patterns instead of this proxy service.
 20:  */
 21: class StandardProxy
 22: {
 23:     const STANDARD_URI = 'Commands.svc';
 24:     const APPLICATION_URI  = 'RestApplication.svc';
 25: 
 26:     protected $http;
 27: 
 28:     protected static $instance;
 29: 
 30:     /**
 31:      * Create a new StandardProxy instance
 32:      *
 33:      * @param RestHttp $http RestHttp instance used for http request.
 34:      * Optionally specify an instance, otherwise use a singleton instance
 35:      */
 36:     public function __construct(RestHttp $http = null)
 37:     {
 38:         $this->http = $http !== null ? $http : RestHttp::instance();
 39:     }
 40: 
 41:     /**
 42:      * Gets singleton instance of Domain.svc proxy
 43:      *
 44:      * @return DomainProxy
 45:      */
 46:     public static function instance()
 47:     {
 48:         if(self::$instance === null)
 49:             self::$instance = new StandardProxy();
 50:         return self::$instance;
 51:     }
 52: 
 53:     /**
 54:      * Insert multiple aggregates with single request to the remote server
 55:      *
 56:      * @param array $aggregates Array of \NGS\Patterns\AggregateRoot instances
 57:      * @return array|mixed
 58:      */
 59:     public function insert(array $aggregates)
 60:     {
 61:         if(empty($aggregates))
 62:             return array();
 63:         $response = $this->persist('POST', $aggregates);
 64:         return RestHttp::parseResult($response);
 65:     }
 66: 
 67:     private static function invalidate(array $aggregates)
 68:     {
 69:         $uris = array();
 70:         foreach($aggregates as $root) {
 71:             $uris[] = $root->URI;
 72:         }
 73:         Repository::instance()->invalidate(get_class($aggregates[0]), $uris);
 74:     }
 75: 
 76:     /**
 77:      * Update multiple aggregates with single command/request
 78:      *
 79:      * @param array $aggregates Array of \NGS\Patterns\AggregateRoot instances
 80:      */
 81:     public function update(array $aggregates)
 82:     {
 83:         if(!empty($aggregates)) {
 84:             $this->persist('PUT', $aggregates);
 85:             self::invalidate($aggregates);
 86:         }
 87:     }
 88: 
 89:     /**
 90:      * Delete multiple aggregates with single command/request
 91:      *
 92:      * @param array $aggregates
 93:      * @return mixed
 94:      * @throws \InvalidArgumentException
 95:      */
 96:     public function delete(array $aggregates)
 97:     {
 98:         if(empty($aggregates))
 99:             return ;
100:         if(!is_object($aggregates[0]))
101:             throw new InvalidArgumentException("Could not delete aggregates. First element was not an object.");
102:         $class = get_class($aggregates[0]);
103:         foreach($aggregates as $index => $item) {
104:             if (!$item instanceof $class) {
105:                 throw new InvalidArgumentException('Could not delete aggregates. Element with index "'.$index.'" was not an instance of "'.$class.'", type was "'.Utils::getType($item).'"');
106:             }
107:             if ($item->URI === null) {
108:                 throw new InvalidArgumentException('Could not delete aggregate element "'.$class.'" with index "'.$index.'". Aggregate URI was null');
109:             }
110:         }
111:         $converter = ObjectConverter::getConverter($class, ObjectConverter::JSON_TYPE);
112:         $body = array(
113:             'RootName' => Name::full($class),
114:             // 'ToDelete' is json encoded inside json
115:             'ToDelete' => $converter::toJson($aggregates)
116:         );
117:         $body = json_encode($body);
118: 
119:         $result = $this->http->sendRequest(
120:             self::APPLICATION_URI.'/PersistAggregateRoot',
121:             'POST',
122:             $body,
123:             array(200, 201));
124:         self::invalidate($aggregates);
125:         return $result;
126:     }
127: 
128:     private function persist($method, array $aggregates)
129:     {
130:         $class = get_class($aggregates[0]);
131:         $name = Name::full($class);
132:         $values = array_map(function($it) { return $it->toArray(); }, $aggregates);
133:         return
134:             $this->http->sendRequest(
135:                 self::STANDARD_URI.'/persist/'.rawurlencode($name),
136:                 $method,
137:                 json_encode($values),
138:                 array(200));
139:     }
140: 
141:     /**
142:      * Perform OLAP analysis on a cube using specification
143:      *
144:      * @return array Results
145:      */
146:     public function olapCubeWithSpecification(
147:         $cube,
148:         $specification,
149:         array $dimensions,
150:         array $facts,
151:         array $order = array())
152:     {
153:         $cube = Name::full($cube);
154:         $name = Name::base($specification);
155:         $fullName = Name::full($specification);
156:         if(strncmp($fullName, $cube, strlen($cube)) != 0)
157:             $name = substr($fullName, 0, strlen($fullName) - strlen($name) - 1).'+'.$name;
158:         $arguments = QueryString::prepareCubeCall($dimensions, $facts, $order);
159:         $response =
160:             $this->http->sendRequest(
161:                 self::STANDARD_URI.'/olap/'.rawurlencode($cube).'?specification='.rawurlencode($name).'&'.$arguments,
162:                 'PUT',
163:                 $specification->toJson(),
164:                 array(201));
165:         return RestHttp::parseResult($response);
166:     }
167: 
168:     /**
169:      * Performs OLAP analysis on a cube
170:      */
171:     public function olapCube(
172:         $cube,
173:         array $dimensions,
174:         array $facts,
175:         array $order = array())
176:     {
177:         $cube = Name::full($cube);
178:         $arguments = QueryString::prepareCubeCall($dimensions, $facts, $order);
179:         $response =
180:             $this->http->sendRequest(
181:                 self::STANDARD_URI.'/olap/'.rawurlencode($cube).'?'.$arguments,
182:                 'GET',
183:                 null,
184:                 array(201));
185:         return RestHttp::parseResult($response);
186:     }
187: 
188:     /**
189:      * Execute custom server service
190:      *
191:      * @return mixed
192:      */
193:     public function execute(
194:         $service,
195:         $body=null
196:     )
197:     {
198:         if(is_array($body))
199:             $body = json_encode($body);
200:         if(!is_string($body) && $body!==null)
201:             throw new InvalidArgumentException("Execute body must be array or string");
202: 
203:         $response =
204:             $this->http->sendRequest(
205:                 self::STANDARD_URI.'/execute/'.rawurlencode($service),
206:                 'POST',
207:                 $body,
208:                 array(200, 201));
209:         return RestHttp::parseResult($response);
210:     }
211: }
212: 
API documentation generated by ApiGen 2.8.0