├── .gitignore ├── README.md ├── composer.json ├── composer.lock └── lib ├── PowerAPI.php └── PowerAPI ├── Data ├── Assignment.php ├── BaseObject.php ├── Section.php └── Student.php ├── Exceptions ├── Authentication.php └── Exception.php ├── Parser.php └── PowerAPI.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Code Climate](http://img.shields.io/codeclimate/github/powerapi/powerapi-php.svg?style=flat-square)](https://codeclimate.com/github/powerapi/powerapi-php) 2 | [![Packagist Version](http://img.shields.io/packagist/v/powerapi/powerapi-php.svg?style=flat-square)](https://packagist.org/packages/powerapi/powerapi-php) 3 | 4 | PowerAPI-php 5 | ============ 6 | Library for fetching information from PowerSchool SISes. 7 | 8 | Requirements 9 | ------------ 10 | * PHP 5 >= 5.1.2. 11 | * PowerSchool 8.x; PowerSchool >= 7.1.0 12 | 13 | Install 14 | ----- 15 | Use [Composer](http://getcomposer.org/) to handle including/downloading 16 | the library and its dependencies for you. 17 | 18 | ``` 19 | $ composer require powerapi/powerapi-php:~3.0 20 | ``` 21 | 22 | For more information on how to install dependencies with Composer, see 23 | Composer's documentation on [installing dependencies](https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies). 24 | 25 | Usage example 26 | ------------- 27 | The following snippet logs into a PowerSchool server and prints the name of 28 | each of the student's sections. 29 | 30 | ```PHP 31 | getMessage()); 38 | } 39 | 40 | foreach ($student->sections as $section) { 41 | echo $section->name."\n"; 42 | } 43 | ``` 44 | 45 | License 46 | ------- 47 | 48 | Copyright (c) 2014 Henri Watson 49 | 50 | Permission is hereby granted, free of charge, to any person obtaining a copy 51 | of this software and associated documentation files (the "Software"), to deal 52 | in the Software without restriction, including without limitation the rights 53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54 | copies of the Software, and to permit persons to whom the Software is 55 | furnished to do so, subject to the following conditions: 56 | 57 | The above copyright notice and this permission notice shall be included in 58 | all copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 66 | THE SOFTWARE. 67 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "powerapi/powerapi-php", 3 | "description": "PHP API for PowerSchool", 4 | "type": "library", 5 | "keywords": ["powerschool"], 6 | "homepage": "https://github.com/powerapi/PowerAPI-php", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Henri Watson", 11 | "email": "henri@henriwatson.com" 12 | } 13 | ], 14 | "repositories": [ 15 | { 16 | "type": "composer", 17 | "url": "https://packages.zendframework.com/" 18 | } 19 | ], 20 | "require": { 21 | "php": ">= 5.1.2", 22 | "zendframework/zend-soap": "~2.3.1" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "PowerAPI\\": "lib/PowerAPI" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "b6fa12caafc1650d913df1b244e81483", 8 | "packages": [ 9 | { 10 | "name": "zendframework/zend-code", 11 | "version": "2.3.3", 12 | "target-dir": "Zend/Code", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/zendframework/Component_ZendCode.git", 16 | "reference": "78ea301533dd05f1c1759e8928d119804900446b" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://packages.zendframework.com/composer/zendframework-zend-code-78ea301533dd05f1c1759e8928d119804900446b-zip-f2a7ed.zip", 21 | "reference": "2.3.3", 22 | "shasum": "571f4f40563a8f05ed9fbf58e1d8d24deefd0674" 23 | }, 24 | "require": { 25 | "php": ">=5.3.23", 26 | "zendframework/zend-eventmanager": "self.version" 27 | }, 28 | "require-dev": { 29 | "doctrine/common": ">=2.1", 30 | "zendframework/zend-stdlib": "self.version" 31 | }, 32 | "suggest": { 33 | "doctrine/common": "Doctrine\\Common >=2.1 for annotation features", 34 | "zendframework/zend-stdlib": "Zend\\Stdlib component" 35 | }, 36 | "type": "library", 37 | "extra": { 38 | "branch-alias": { 39 | "dev-master": "2.3-dev", 40 | "dev-develop": "2.4-dev" 41 | } 42 | }, 43 | "autoload": { 44 | "psr-0": { 45 | "Zend\\Code\\": "" 46 | } 47 | }, 48 | "license": [ 49 | "BSD-3-Clause" 50 | ], 51 | "description": "provides facilities to generate arbitrary code using an object oriented interface", 52 | "homepage": "https://github.com/zendframework/zf2", 53 | "keywords": [ 54 | "code", 55 | "zf2" 56 | ], 57 | "support": { 58 | "source": "https://github.com/zendframework/Component_ZendCode/tree/release-2.3.3" 59 | }, 60 | "time": "2014-09-16 22:58:11" 61 | }, 62 | { 63 | "name": "zendframework/zend-escaper", 64 | "version": "2.3.3", 65 | "target-dir": "Zend/Escaper", 66 | "source": { 67 | "type": "git", 68 | "url": "https://github.com/zendframework/Component_ZendEscaper.git", 69 | "reference": "c24949840766a544489bfc303714e1f332341010" 70 | }, 71 | "dist": { 72 | "type": "zip", 73 | "url": "https://packages.zendframework.com/composer/zendframework-zend-escaper-c24949840766a544489bfc303714e1f332341010-zip-c66566.zip", 74 | "reference": "2.3.3", 75 | "shasum": "2a5ca9aa9fa325d315479488d1cc98ff0539443b" 76 | }, 77 | "require": { 78 | "php": ">=5.3.23" 79 | }, 80 | "type": "library", 81 | "extra": { 82 | "branch-alias": { 83 | "dev-master": "2.3-dev", 84 | "dev-develop": "2.4-dev" 85 | } 86 | }, 87 | "autoload": { 88 | "psr-0": { 89 | "Zend\\Escaper\\": "" 90 | } 91 | }, 92 | "license": [ 93 | "BSD-3-Clause" 94 | ], 95 | "description": " ", 96 | "homepage": "https://github.com/zendframework/zf2", 97 | "keywords": [ 98 | "escaper", 99 | "zf2" 100 | ], 101 | "support": { 102 | "source": "https://github.com/zendframework/Component_ZendEscaper/tree/release-2.3.3" 103 | }, 104 | "time": "2014-09-16 22:58:11" 105 | }, 106 | { 107 | "name": "zendframework/zend-eventmanager", 108 | "version": "2.3.3", 109 | "target-dir": "Zend/EventManager", 110 | "source": { 111 | "type": "git", 112 | "url": "https://github.com/zendframework/Component_ZendEventManager.git", 113 | "reference": "4110fe64b10616b9bb71429a206d8e9e6d99e3ba" 114 | }, 115 | "dist": { 116 | "type": "zip", 117 | "url": "https://packages.zendframework.com/composer/zendframework-zend-eventmanager-4110fe64b10616b9bb71429a206d8e9e6d99e3ba-zip-f2e466.zip", 118 | "reference": "2.3.3", 119 | "shasum": "f0005036e196d31bcd41f5461653d4b63fc14132" 120 | }, 121 | "require": { 122 | "php": ">=5.3.23", 123 | "zendframework/zend-stdlib": "self.version" 124 | }, 125 | "type": "library", 126 | "extra": { 127 | "branch-alias": { 128 | "dev-master": "2.3-dev", 129 | "dev-develop": "2.4-dev" 130 | } 131 | }, 132 | "autoload": { 133 | "psr-0": { 134 | "Zend\\EventManager\\": "" 135 | } 136 | }, 137 | "license": [ 138 | "BSD-3-Clause" 139 | ], 140 | "description": " ", 141 | "homepage": "https://github.com/zendframework/zf2", 142 | "keywords": [ 143 | "eventmanager", 144 | "zf2" 145 | ], 146 | "support": { 147 | "source": "https://github.com/zendframework/Component_ZendEventManager/tree/release-2.3.3" 148 | }, 149 | "time": "2014-09-16 22:58:11" 150 | }, 151 | { 152 | "name": "zendframework/zend-server", 153 | "version": "2.3.3", 154 | "target-dir": "Zend/Server", 155 | "source": { 156 | "type": "git", 157 | "url": "https://github.com/zendframework/Component_ZendServer.git", 158 | "reference": "2c074755ddf63598c703482ca21c721d63d990b0" 159 | }, 160 | "dist": { 161 | "type": "zip", 162 | "url": "https://packages.zendframework.com/composer/zendframework-zend-server-2c074755ddf63598c703482ca21c721d63d990b0-zip-d8f0ad.zip", 163 | "reference": "2.3.3", 164 | "shasum": "3d4718f65cec08530a16c2174ba370b80ea49d04" 165 | }, 166 | "require": { 167 | "php": ">=5.3.23", 168 | "zendframework/zend-code": "self.version", 169 | "zendframework/zend-stdlib": "self.version" 170 | }, 171 | "type": "library", 172 | "extra": { 173 | "branch-alias": { 174 | "dev-master": "2.3-dev", 175 | "dev-develop": "2.4-dev" 176 | } 177 | }, 178 | "autoload": { 179 | "psr-0": { 180 | "Zend\\Server\\": "" 181 | } 182 | }, 183 | "license": [ 184 | "BSD-3-Clause" 185 | ], 186 | "description": " ", 187 | "homepage": "https://github.com/zendframework/zf2", 188 | "keywords": [ 189 | "server", 190 | "zf2" 191 | ], 192 | "support": { 193 | "source": "https://github.com/zendframework/Component_ZendServer/tree/release-2.3.3" 194 | }, 195 | "time": "2014-09-16 22:58:11" 196 | }, 197 | { 198 | "name": "zendframework/zend-soap", 199 | "version": "2.3.3", 200 | "target-dir": "Zend/Soap", 201 | "source": { 202 | "type": "git", 203 | "url": "https://github.com/zendframework/Component_ZendSoap.git", 204 | "reference": "091a4e72d3d3e1c2e8a5885d3a4e10c5d394678b" 205 | }, 206 | "dist": { 207 | "type": "zip", 208 | "url": "https://packages.zendframework.com/composer/zendframework-zend-soap-091a4e72d3d3e1c2e8a5885d3a4e10c5d394678b-zip-0018ef.zip", 209 | "reference": "2.3.3", 210 | "shasum": "600c5b0dc7f8e862f9d54fa6abf5cb2d908f5e9b" 211 | }, 212 | "require": { 213 | "php": ">=5.3.23", 214 | "zendframework/zend-server": "self.version", 215 | "zendframework/zend-stdlib": "self.version", 216 | "zendframework/zend-uri": "self.version" 217 | }, 218 | "require-dev": { 219 | "zendframework/zend-http": "self.version" 220 | }, 221 | "suggest": { 222 | "zendframework/zend-http": "Zend\\Http component" 223 | }, 224 | "type": "library", 225 | "extra": { 226 | "branch-alias": { 227 | "dev-master": "2.3-dev", 228 | "dev-develop": "2.4-dev" 229 | } 230 | }, 231 | "autoload": { 232 | "psr-0": { 233 | "Zend\\Soap\\": "" 234 | } 235 | }, 236 | "license": [ 237 | "BSD-3-Clause" 238 | ], 239 | "description": " ", 240 | "homepage": "https://github.com/zendframework/zf2", 241 | "keywords": [ 242 | "soap", 243 | "zf2" 244 | ], 245 | "support": { 246 | "source": "https://github.com/zendframework/Component_ZendSoap/tree/release-2.3.3" 247 | }, 248 | "time": "2014-09-16 22:58:11" 249 | }, 250 | { 251 | "name": "zendframework/zend-stdlib", 252 | "version": "2.3.3", 253 | "target-dir": "Zend/Stdlib", 254 | "source": { 255 | "type": "git", 256 | "url": "https://github.com/zendframework/Component_ZendStdlib.git", 257 | "reference": "fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33" 258 | }, 259 | "dist": { 260 | "type": "zip", 261 | "url": "https://packages.zendframework.com/composer/zendframework-zend-stdlib-fa33e6647f830d0d2a1cb451efcdfe1bb9a66c33-zip-3307db.zip", 262 | "reference": "2.3.3", 263 | "shasum": "9ba6087a66196914c6ff6885f78eec7bc7352517" 264 | }, 265 | "require": { 266 | "php": ">=5.3.23" 267 | }, 268 | "require-dev": { 269 | "zendframework/zend-eventmanager": "self.version", 270 | "zendframework/zend-serializer": "self.version", 271 | "zendframework/zend-servicemanager": "self.version" 272 | }, 273 | "suggest": { 274 | "zendframework/zend-eventmanager": "To support aggregate hydrator usage", 275 | "zendframework/zend-serializer": "Zend\\Serializer component", 276 | "zendframework/zend-servicemanager": "To support hydrator plugin manager usage" 277 | }, 278 | "type": "library", 279 | "extra": { 280 | "branch-alias": { 281 | "dev-master": "2.3-dev", 282 | "dev-develop": "2.4-dev" 283 | } 284 | }, 285 | "autoload": { 286 | "psr-0": { 287 | "Zend\\Stdlib\\": "" 288 | } 289 | }, 290 | "license": [ 291 | "BSD-3-Clause" 292 | ], 293 | "description": " ", 294 | "homepage": "https://github.com/zendframework/zf2", 295 | "keywords": [ 296 | "stdlib", 297 | "zf2" 298 | ], 299 | "support": { 300 | "source": "https://github.com/zendframework/Component_ZendStdlib/tree/release-2.3.3" 301 | }, 302 | "time": "2014-09-16 22:58:11" 303 | }, 304 | { 305 | "name": "zendframework/zend-uri", 306 | "version": "2.3.3", 307 | "target-dir": "Zend/Uri", 308 | "source": { 309 | "type": "git", 310 | "url": "https://github.com/zendframework/Component_ZendUri.git", 311 | "reference": "2a62a92888d7cbae1177fa5f58b0bfcf717aea53" 312 | }, 313 | "dist": { 314 | "type": "zip", 315 | "url": "https://packages.zendframework.com/composer/zendframework-zend-uri-2a62a92888d7cbae1177fa5f58b0bfcf717aea53-zip-ef33a3.zip", 316 | "reference": "2.3.3", 317 | "shasum": "bacb5f752fa65407e5e60d66b43d086f2872c7a3" 318 | }, 319 | "require": { 320 | "php": ">=5.3.23", 321 | "zendframework/zend-escaper": "self.version", 322 | "zendframework/zend-validator": "self.version" 323 | }, 324 | "type": "library", 325 | "extra": { 326 | "branch-alias": { 327 | "dev-master": "2.3-dev", 328 | "dev-develop": "2.4-dev" 329 | } 330 | }, 331 | "autoload": { 332 | "psr-0": { 333 | "Zend\\Uri\\": "" 334 | } 335 | }, 336 | "license": [ 337 | "BSD-3-Clause" 338 | ], 339 | "description": "a component that aids in manipulating and validating » Uniform Resource Identifiers (URIs)", 340 | "homepage": "https://github.com/zendframework/zf2", 341 | "keywords": [ 342 | "uri", 343 | "zf2" 344 | ], 345 | "support": { 346 | "source": "https://github.com/zendframework/Component_ZendUri/tree/release-2.3.3" 347 | }, 348 | "time": "2014-09-16 22:58:11" 349 | }, 350 | { 351 | "name": "zendframework/zend-validator", 352 | "version": "2.3.3", 353 | "target-dir": "Zend/Validator", 354 | "source": { 355 | "type": "git", 356 | "url": "https://github.com/zendframework/Component_ZendValidator.git", 357 | "reference": "2881dfaff8452d8cbdaa8ad8a9faccce9843fc6a" 358 | }, 359 | "dist": { 360 | "type": "zip", 361 | "url": "https://packages.zendframework.com/composer/zendframework-zend-validator-2881dfaff8452d8cbdaa8ad8a9faccce9843fc6a-zip-02f502.zip", 362 | "reference": "2.3.3", 363 | "shasum": "5f5d643ff6beeea896c9e7738c8be09a8f9fdfbf" 364 | }, 365 | "require": { 366 | "php": ">=5.3.23", 367 | "zendframework/zend-stdlib": "self.version" 368 | }, 369 | "require-dev": { 370 | "zendframework/zend-db": "self.version", 371 | "zendframework/zend-filter": "self.version", 372 | "zendframework/zend-i18n": "self.version", 373 | "zendframework/zend-math": "self.version", 374 | "zendframework/zend-servicemanager": "self.version", 375 | "zendframework/zend-session": "self.version", 376 | "zendframework/zend-uri": "self.version" 377 | }, 378 | "suggest": { 379 | "zendframework/zend-db": "Zend\\Db component", 380 | "zendframework/zend-filter": "Zend\\Filter component, required by the Digits validator", 381 | "zendframework/zend-i18n": "Zend\\I18n component to allow translation of validation error messages as well as to use the various Date validators", 382 | "zendframework/zend-math": "Zend\\Math component", 383 | "zendframework/zend-resources": "Translations of validator messages", 384 | "zendframework/zend-servicemanager": "Zend\\ServiceManager component to allow using the ValidatorPluginManager and validator chains", 385 | "zendframework/zend-session": "Zend\\Session component", 386 | "zendframework/zend-uri": "Zend\\Uri component, required by the Uri and Sitemap\\Loc validators" 387 | }, 388 | "type": "library", 389 | "extra": { 390 | "branch-alias": { 391 | "dev-master": "2.3-dev", 392 | "dev-develop": "2.4-dev" 393 | } 394 | }, 395 | "autoload": { 396 | "psr-0": { 397 | "Zend\\Validator\\": "" 398 | } 399 | }, 400 | "license": [ 401 | "BSD-3-Clause" 402 | ], 403 | "description": "provides a set of commonly needed validators", 404 | "homepage": "https://github.com/zendframework/zf2", 405 | "keywords": [ 406 | "validator", 407 | "zf2" 408 | ], 409 | "support": { 410 | "source": "https://github.com/zendframework/Component_ZendValidator/tree/release-2.3.3" 411 | }, 412 | "time": "2014-09-16 22:58:11" 413 | } 414 | ], 415 | "packages-dev": [ 416 | 417 | ], 418 | "aliases": [ 419 | 420 | ], 421 | "minimum-stability": "stable", 422 | "stability-flags": [ 423 | 424 | ], 425 | "prefer-stable": false, 426 | "platform": { 427 | "php": ">= 5.1.2" 428 | }, 429 | "platform-dev": [ 430 | 431 | ] 432 | } 433 | -------------------------------------------------------------------------------- /lib/PowerAPI.php: -------------------------------------------------------------------------------- 1 | details['category'] = $details['category']->name; 22 | $this->details['description'] = $details['assignment']->description; 23 | $this->details['name'] = $details['assignment']->name; 24 | if ($details['score'] !== null) { 25 | $this->details['percent'] = $details['score']->percent; 26 | $this->details['score'] = $details['score']->score; 27 | } else { 28 | $this->details['percent'] = null; 29 | $this->details['score'] = null; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/PowerAPI/Data/BaseObject.php: -------------------------------------------------------------------------------- 1 | details = $details; 21 | } 22 | 23 | /** 24 | * Returns a value from the details store 25 | * @param string $name key for the value to be returned 26 | * @return mixed value 27 | */ 28 | public function __get($name) 29 | { 30 | return $this->details[$name]; 31 | } 32 | 33 | /** 34 | * Checks if a key exists in the details store 35 | * @param string $name key to be checked 36 | * @return boolean 37 | */ 38 | public function __isset($name) 39 | { 40 | return isset($this->details[$name]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/PowerAPI/Data/Section.php: -------------------------------------------------------------------------------- 1 | details['assignments'] = $details['assignments']; 23 | 24 | $this->details['expression'] = $details['section']->expression; 25 | 26 | if ($details['finalGrades'] !== null) { 27 | $this->details['finalGrades'] = Array(); 28 | 29 | foreach ($details['finalGrades'] as $finalGrade) { 30 | $this->details['finalGrades'][ 31 | $details['reportingTerms'][$finalGrade->reportingTermId] 32 | ] = $finalGrade->percent; 33 | } 34 | } else { 35 | $this->details['finalGrades'] = null; 36 | } 37 | 38 | $this->details['name'] = $details['section']->schoolCourseTitle; 39 | $this->details['roomName'] = $details['section']->roomName; 40 | $this->details['teacher'] = Array( 41 | 'firstName' => $details['teacher']->firstName, 42 | 'lastName' => $details['teacher']->lastName, 43 | 'email' => $details['teacher']->email, 44 | 'schoolPhone' => $details['teacher']->schoolPhone 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/PowerAPI/Data/Student.php: -------------------------------------------------------------------------------- 1 | soap_url = $soap_url; 31 | $this->soap_session = $soap_session; 32 | 33 | $this->details['information'] = Array(); 34 | $this->details['sections'] = Array(); 35 | 36 | if ($populate) { 37 | $this->populate(); 38 | } 39 | } 40 | 41 | /** 42 | * Pull the authenticated user's transcript from the server and parses it. 43 | * @return null 44 | */ 45 | public function populate() 46 | { 47 | $transcript = $this->fetchTranscript(); 48 | $this->parseTranscript($transcript); 49 | } 50 | 51 | /** 52 | * Fetches the user's transcript from the server and returns it. 53 | * @return array user's transcript as returned by PowerSchool 54 | */ 55 | public function fetchTranscript() 56 | { 57 | $client = new \Zend\Soap\Client(); 58 | $client->setOptions(Array( 59 | 'uri' => 'http://publicportal.rest.powerschool.pearson.com/xsd', 60 | 'location' => $this->soap_url.'pearson-rest/services/PublicPortalServiceJSON', 61 | 'login' => 'pearson', 62 | 'password' => 'm0bApP5', 63 | 'use' => SOAP_LITERAL 64 | )); 65 | 66 | // This is a workaround for SoapClient not having a WSDL to go off of. 67 | // Passing everything as an object or as an associative array causes 68 | // the parameters to not be correctly interpreted by PowerSchool. 69 | $parameters = Array( 70 | 'userSessionVO' => (object) Array( 71 | 'userId' => $this->soap_session->userId, 72 | 'serviceTicket' => $this->soap_session->serviceTicket, 73 | 'serverInfo' => (object) Array( 74 | 'apiVersion' => $this->soap_session->serverInfo->apiVersion 75 | ), 76 | 'serverCurrentTime' => $this->soap_session->serverCurrentTime, 77 | 'userType' => $this->soap_session->userType 78 | ), 79 | 'studentIDs' => $this->soap_session->studentIDs, 80 | 'qil' => (object) Array( 81 | 'includes' => '1' 82 | ) 83 | ); 84 | 85 | $transcript = $client->__call('getStudentData', $parameters); 86 | 87 | return $transcript; 88 | } 89 | 90 | /** 91 | * Parses the passed transcript and populates $this with its contents. 92 | * @param object $transcript transcript from fetchTranscript() 93 | * @return void 94 | */ 95 | public function parseTranscript($transcript) 96 | { 97 | $studentData = $transcript->studentDataVOs; 98 | 99 | $this->details['information'] = $studentData->student; 100 | 101 | $assignmentCategories = \PowerAPI\Parser::assignmentCategories($studentData->assignmentCategories); 102 | $assignmentScores = \PowerAPI\Parser::assignmentScores($studentData->assignmentScores); 103 | $finalGrades = \PowerAPI\Parser::finalGrades($studentData->finalGrades); 104 | $reportingTerms = \PowerAPI\Parser::reportingTerms($studentData->reportingTerms); 105 | $teachers = \PowerAPI\Parser::teachers($studentData->teachers); 106 | 107 | $assignments = \PowerAPI\Parser::assignments( 108 | $studentData->assignments, 109 | $assignmentCategories, 110 | $assignmentScores 111 | ); 112 | 113 | $this->details['sections'] = \PowerAPI\Parser::sections( 114 | $studentData->sections, 115 | $assignments, 116 | $finalGrades, 117 | $reportingTerms, 118 | $teachers 119 | ); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /lib/PowerAPI/Exceptions/Authentication.php: -------------------------------------------------------------------------------- 1 | sectionid])) { 22 | $assignments[$assignment->sectionid] = Array(); 23 | } 24 | 25 | $assignments[$assignment->sectionid][] = new Data\Assignment(Array( 26 | 'assignment' => $assignment, 27 | 'category' => $assignmentCategories[$assignment->categoryId], 28 | 'score' => Parser::requireDefined($assignmentScores[$assignment->id]) 29 | )); 30 | } 31 | 32 | return $assignments; 33 | } 34 | 35 | /** Group an assignmentCategories dump by section ID 36 | * @param array $rawAssignmentCategories assignment categories dump to be parsed 37 | * @return array assignment categories grouped by category ID 38 | */ 39 | static public function assignmentCategories($rawAssignmentCategories) 40 | { 41 | $assignmentCategories = Array(); 42 | 43 | if(!is_array($rawAssignmentCategories)) $rawAssignmentCategories = Array($rawAssignmentCategories); 44 | foreach ($rawAssignmentCategories as $assignmentCategory) { 45 | $assignmentCategories[$assignmentCategory->id] = $assignmentCategory; 46 | } 47 | 48 | return $assignmentCategories; 49 | } 50 | 51 | /** Group an assignmentScores dump by section ID 52 | * @param array $rawAssignmentScores assignment scores dump to be parsed 53 | * @return array assignment scores grouped by assignment ID 54 | */ 55 | static public function assignmentScores($rawAssignmentScores) 56 | { 57 | $assignmentScores = Array(); 58 | 59 | if(!is_array($rawAssignmentScores)) $rawAssignmentScores = Array($rawAssignmentScores); 60 | foreach ($rawAssignmentScores as $assignmentScore) { 61 | $assignmentScores[$assignmentScore->assignmentId] = $assignmentScore; 62 | } 63 | 64 | return $assignmentScores; 65 | } 66 | 67 | /** Group a finalGrades dump by section ID 68 | * @param array $rawFinalGrades final grades dump to be parsed 69 | * @return array final grades grouped by section ID 70 | */ 71 | static public function finalGrades($rawFinalGrades) 72 | { 73 | $finalGrades = Array(); 74 | 75 | if(!is_array($rawFinalGrades)) $rawFinalGrades = Array($rawFinalGrades); 76 | foreach ($rawFinalGrades as $finalGrade) { 77 | if (!isset($finalGrades[$finalGrade->sectionid])) { 78 | $finalGrades[$finalGrade->sectionid] = []; 79 | } 80 | 81 | $finalGrades[$finalGrade->sectionid][] = $finalGrade; 82 | } 83 | 84 | return $finalGrades; 85 | } 86 | 87 | /** Group a reportingTerms dump by term ID 88 | * @param array $rawReportingTerms reporting terms dump to be parsed 89 | * @return array reporting terms grouped by term ID 90 | */ 91 | static public function reportingTerms($rawReportingTerms) 92 | { 93 | $reportingTerms = Array(); 94 | 95 | if(!is_array($rawReportingTerms)) $rawReportingTerms = Array($rawReportingTerms); 96 | foreach ($rawReportingTerms as $reportingTerm) { 97 | $reportingTerms[$reportingTerm->id] = $reportingTerm->abbreviation; 98 | } 99 | 100 | return $reportingTerms; 101 | } 102 | 103 | /** Check if $a should be displayed before or after $b 104 | * @param array $a section A 105 | * @param array $b section B 106 | * @return int -1 if $a should go first, 0 if $a = $b, 1 if $b should go first 107 | */ 108 | static public function sectionsSort($a, $b) 109 | { 110 | if ($a->expression !== $b->expression) { 111 | return strcmp($a->expression, $b->expression); 112 | } else { 113 | return strcmp($a->name, $b->name); 114 | } 115 | } 116 | 117 | /** Create a Section object for each section 118 | * @param array $rawSections sections dump to be parsed 119 | * @param array $assignments array of assignments grouped by section ID 120 | * @param array $finalGrades array of final grades grouped by section ID 121 | * @param array $reportingTerms array of reporting terms grouped by term ID 122 | * @param array $teachers array of teachers grouped by teacher ID 123 | * @return array 124 | */ 125 | static public function sections($rawSections, $assignments, $finalGrades, $reportingTerms, $teachers) 126 | { 127 | $sections = Array(); 128 | 129 | if(!is_array($rawSections)) $rawSections = Array($rawSections); 130 | foreach ($rawSections as $section) { 131 | // PowerSchool will return sections that have not started yet. 132 | // These are stripped since none of the official channels display them. 133 | if (strtotime($section->enrollments->startDate) > time()) { 134 | continue; 135 | } 136 | 137 | $sections[] = new Data\Section(Array( 138 | 'assignments' => Parser::requireDefined($assignments[$section->id]), 139 | 'finalGrades' => Parser::requireDefined($finalGrades[$section->id]), 140 | 'reportingTerms' => $reportingTerms, 141 | 'section' => $section, 142 | 'teacher' => $teachers[$section->teacherID] 143 | )); 144 | } 145 | 146 | usort($sections, array('PowerAPI\Parser', 'sectionsSort')); 147 | 148 | return $sections; 149 | } 150 | 151 | /** Group a teachers dump by teacher ID 152 | * @param array $rawTeachers teachers dump to be parsed 153 | * @return array teachers grouped by teacher ID 154 | */ 155 | static public function teachers($rawTeachers) 156 | { 157 | $teachers = Array(); 158 | 159 | if(!is_array($rawTeachers)) $rawTeachers = Array($rawTeachers); 160 | foreach ($rawTeachers as $teacher) { 161 | $teachers[$teacher->id] = $teacher; 162 | } 163 | 164 | return $teachers; 165 | } 166 | 167 | /** 168 | * Return null if the passed value does not exist or the value if it does 169 | * @param mixed $value value to be examined and possibly returned 170 | * @return mixed null or the passed parameter 171 | */ 172 | static public function requireDefined(&$value) 173 | { 174 | if (isset($value)) { 175 | return $value; 176 | } else { 177 | return null; 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /lib/PowerAPI/PowerAPI.php: -------------------------------------------------------------------------------- 1 | setOptions(Array( 27 | 'uri' => 'http://publicportal.rest.powerschool.pearson.com/xsd', 28 | 'location' => $url.'pearson-rest/services/PublicPortalServiceJSON', 29 | 'login' => 'pearson', 30 | 'password' => 'm0bApP5', 31 | 'use' => SOAP_LITERAL 32 | )); 33 | 34 | $login = $client->__call( 35 | 'loginToPublicPortal', 36 | Array( 37 | 'username' => $username, 38 | 'password' => $password 39 | ) 40 | ); 41 | 42 | // userSessionVO is unset if something went wrong during auth. 43 | if ($login->userSessionVO === null) { 44 | throw(new Exceptions\Authentication($login->messageVOs->description)); 45 | } 46 | 47 | $session = $login->userSessionVO; 48 | 49 | return new Data\Student($url, $session, $fetch_transcript); 50 | } 51 | 52 | /** 53 | * Fetch a URL for a PowerSchool install using a district code 54 | * @param string $code district code 55 | * @return string 56 | */ 57 | static public function districtLookup($code) 58 | { 59 | $curlResource = curl_init('https://powersource.pearsonschoolsystems.com/services/rest/remote-device/v2/get-district/'.$code); 60 | curl_setopt($curlResource, CURLOPT_RETURNTRANSFER, true); 61 | curl_setopt($curlResource, CURLOPT_HTTPHEADER, array( 62 | 'Accept: application/json' 63 | )); 64 | 65 | $details = curl_exec($curlResource); 66 | 67 | // Return false if we couldn't connect or if the district doesn't exist. 68 | if ($details === FALSE || $details === '') { 69 | return false; 70 | } 71 | 72 | $details = json_decode($details); 73 | 74 | if ($details->district->server->sslEnabled !== 1) { 75 | $url = 'https://'.$details->district->server->serverAddress; 76 | } else { 77 | $url = 'http://'.$details->district->server->serverAddress; 78 | } 79 | 80 | if ( 81 | ($details->district->server->sslEnabled == 1 && $details->district->server->portNumber == 443) || 82 | ($details->district->server->sslEnabled == 0 && $details->district->server->portNumber == 80) 83 | ) { 84 | $url .= '/'; 85 | } else { 86 | $url .= ':'.$details->district->server->portNumber.'/'; 87 | } 88 | 89 | return $url; 90 | } 91 | } 92 | --------------------------------------------------------------------------------