├── composer.json ├── LICENSE ├── README.md ├── example.php └── TextRazor.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "textrazor/textrazor-php", 3 | "type": "library", 4 | "description": "PHP SDK for the TextRazor Text Analytics API", 5 | "keywords": [ 6 | "TextRazor", 7 | "API", 8 | "Client" 9 | ], 10 | "homepage": "https://github.com/TextRazor/textrazor-php", 11 | "license": "MIT", 12 | "require": { 13 | "ext-curl": "*", 14 | "php": ">=5.6.0" 15 | }, 16 | "autoload": { 17 | "classmap": [ 18 | "." 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Toby Crayston 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TextRazor/textrazor-php 2 | 3 | **PHP SDK for the TextRazor Text Analytics API.** 4 | 5 | TextRazor offers state-of-the-art natural language processing tools through a simple API, allowing you to build semantic technology into your applications in minutes. 6 | 7 | Hundreds of applications rely on TextRazor to understand unstructured text across a range of verticals, with use cases including social media monitoring, enterprise search, recommendation systems and ad targeting. 8 | 9 | Read more about the TextRazor API at [https://www.textrazor.com](https://www.textrazor.com). 10 | 11 | ## Getting Started 12 | 13 | - Get a free API key from [https://www.textrazor.com](https://www.textrazor.com/signup). 14 | 15 | ### The classic way 16 | 17 | - Copy the file `TextRazor.php` into your project and load the class via `require_once 'TextRazor.php';`. 18 | 19 | ### The Composer way 20 | 21 | ``` 22 | composer require textrazor/textrazor-php 23 | ``` 24 | 25 | ### Example 26 | 27 | - Create an instance of the TextRazor object and start analyzing your text. 28 | 29 | ```php 30 | addExtractor('entities'); 40 | 41 | $response = $textrazor->analyze($text); 42 | if (isset($response['response']['entities'])) { 43 | foreach ($response['response']['entities'] as $entity) { 44 | print_r($entity['entityId'] . PHP_EOL); 45 | } 46 | } 47 | ``` 48 | 49 | ## Documentation 50 | 51 | Please visit the [TextRazor PHP Reference](https://www.textrazor.com/docs/php). 52 | 53 | ## Error Handling 54 | 55 | The TextRazor PHP SDK throws an exception with a helpful error message in the case of bad inputs, TextRazor errors, or network errors. 56 | 57 | ## Encoding 58 | 59 | TextRazor expects all text to be encoded as UTF-8. Please make sure all your content is encoded to valid UTF-8 before calling the `analyze` method, or the service will return an error. 60 | 61 | ## Response 62 | 63 | PHP makes it really easy to manipulate the JSON response from the server. You can find more information about the various fields at [https://www.textrazor.com/docs/rest]( https://www.textrazor.com/docs/rest). 64 | 65 | ## Appendix 66 | 67 | If you have any queries please contact us at support@textrazor.com and we will get back to you promptly. We’d also love to hear from you if you have any ideas for improving the API or documentation. 68 | -------------------------------------------------------------------------------- /example.php: -------------------------------------------------------------------------------- 1 | getAccount()); 10 | } 11 | 12 | function testAnalysis() 13 | { 14 | $textrazor = new TextRazor(); 15 | 16 | $textrazor->addExtractor('entities'); 17 | $textrazor->addExtractor('words'); 18 | $textrazor->addExtractor('spelling'); 19 | 20 | $text = 'LONDON - Barclays misled shareholders and the public about one of the biggest investments in the banks history, a BBC Panorama investigation has found.'; 21 | 22 | $response = $textrazor->analyze($text); 23 | if (isset($response['response']['entities'])) { 24 | foreach ($response['response']['entities'] as $entity) { 25 | print('Entity ID: ' . $entity['entityId']); 26 | print(PHP_EOL); 27 | } 28 | } 29 | } 30 | 31 | function testClassifier() 32 | { 33 | $textrazorClassifier = new ClassifierManager(); 34 | 35 | $classifierId = 'test_cats_php'; 36 | 37 | try { 38 | print_r($textrazorClassifier->deleteClassifier($classifierId)); 39 | } catch (Exception $e) { 40 | // Silently ignore missing classifier for now. 41 | } 42 | 43 | // Define some new categories and upload them as a new classifier. 44 | $newCategories = []; 45 | array_push($newCategories, ['categoryId' => '1', 'query' => 'concept("banking")']); 46 | array_push($newCategories, ['categoryId' => '2', 'query' => 'concept("health")']); 47 | 48 | $textrazorClassifier->createClassifier($classifierId, $newCategories); 49 | 50 | // Test the new classifier out with an analysis request. 51 | $textrazor = new TextRazor(); 52 | $textrazor->addClassifier($classifierId); 53 | 54 | $text = 'Barclays misled shareholders and the public about one of the biggest investments in the banks history, a BBC Panorama investigation has found.'; 55 | $response = $textrazor->analyze($text); 56 | 57 | print_r($response['response']); 58 | 59 | // The client offers various methods for manipulating your stored classifier. 60 | print_r($textrazorClassifier->allCategories($classifierId)); 61 | 62 | print_r($textrazorClassifier->deleteClassifier($classifierId)); 63 | } 64 | 65 | function testEntityDictionary() 66 | { 67 | $textrazorDictionary = new DictionaryManager(); 68 | 69 | $dictionaryId = 'test_ents_php'; 70 | 71 | try { 72 | print_r($textrazorDictionary->deleteDictionary($dictionaryId)); 73 | } catch (Exception $e) { 74 | // Silently ignore missing dictionary for now. 75 | } 76 | 77 | // Define a new dictionary, then add some test entries 78 | print_r($textrazorDictionary->createDictionary($dictionaryId, 'STEM', true, 'eng')); 79 | 80 | $newEntities = []; 81 | array_push($newEntities, ['id' => 'TV_1', 'text' => 'BBC Panorama']); 82 | 83 | print_r($textrazorDictionary->addEntries($dictionaryId, $newEntities)); 84 | 85 | // To use the new dictionary, simply add its ID to your analysis request. 86 | 87 | $textrazor = new TextRazor(); 88 | 89 | $textrazor->addEntityDictionary($dictionaryId); 90 | 91 | $text = 'Barclays misled shareholders and the public about one of the biggest investments in the banks history, a BBC Panorama investigation has found.'; 92 | $response = $textrazor->analyze($text); 93 | 94 | // The matched entities will be available in the response 95 | 96 | print_r($response['response']['entities']); 97 | 98 | // The client offers various methods for manipulating your stored dictionary entries. 99 | 100 | print_r($textrazorDictionary->getEntry($dictionaryId, 'TV_1')); 101 | 102 | print_r($textrazorDictionary->allEntries($dictionaryId, 10)); 103 | 104 | print_r($textrazorDictionary->getDictionary($dictionaryId)); 105 | 106 | print_r($textrazorDictionary->allDictionaries()); 107 | 108 | print_r($textrazorDictionary->deleteDictionary($dictionaryId)); 109 | } 110 | 111 | testAccount(); 112 | testAnalysis(); 113 | testEntityDictionary(); 114 | testClassifier(); 115 | -------------------------------------------------------------------------------- /TextRazor.php: -------------------------------------------------------------------------------- 1 | add($key, $listItem); 15 | } 16 | } elseif (is_bool($value)) { 17 | $this->add($key, $value ? 'true' : 'false'); 18 | } else { 19 | $this->params[] = urlencode($key) . '=' . urlencode($value); 20 | } 21 | } 22 | 23 | public function build() 24 | { 25 | return implode('&', $this->params); 26 | } 27 | } 28 | 29 | /** 30 | * Represents global settings common to all TextRazor operations. Settings can be 31 | * enabled here, or with each request. 32 | */ 33 | class TextRazorSettings 34 | { 35 | private static $apiKey; 36 | 37 | private static $endPoint = 'http://api.textrazor.com/'; 38 | 39 | private static $secureEndPoint = 'https://api.textrazor.com/'; 40 | 41 | private static $enableEncryption = true; 42 | 43 | private static $enableCompression = true; 44 | 45 | // TextRazor has an internal timeout of 30 seconds, after which it will return an error. 46 | // We set a higher default here to prevent any transport issues causing a client hang. 47 | private static $connectTimeoutSeconds = 120; 48 | 49 | private static $timeoutSeconds = 120; 50 | 51 | public static function getApiKey() 52 | { 53 | return self::$apiKey; 54 | } 55 | 56 | public static function setApiKey($apiKey) 57 | { 58 | if ( ! is_string($apiKey)) { 59 | throw new Exception('TextRazor Error: Invalid API Key'); 60 | } 61 | 62 | self::$apiKey = $apiKey; 63 | } 64 | 65 | public static function getEndPoint() 66 | { 67 | return self::$endPoint; 68 | } 69 | 70 | public static function setEndPoint($endPoint) 71 | { 72 | if ( ! is_string($endPoint)) { 73 | throw new Exception('TextRazor Error: Invalid HTTP Endpoint'); 74 | } 75 | 76 | self::$endPoint = $endPoint; 77 | } 78 | 79 | public static function getSecureEndPoint() 80 | { 81 | return self::$secureEndPoint; 82 | } 83 | 84 | public static function setSecureEndPoint($endPoint) 85 | { 86 | if ( ! is_string($endPoint)) { 87 | throw new Exception('TextRazor Error: Invalid HTTPS Endpoint'); 88 | } 89 | 90 | self::$secureEndPoint = $endPoint; 91 | } 92 | 93 | public static function getEnableCompression() 94 | { 95 | return self::$enableCompression; 96 | } 97 | 98 | public static function setEnableCompression($enableCompression) 99 | { 100 | if ( ! is_bool($enableCompression)) { 101 | throw new Exception('TextRazor Error: enableCompression must be a bool'); 102 | } 103 | 104 | self::$enableCompression = $enableCompression; 105 | } 106 | 107 | public static function getEnableEncryption() 108 | { 109 | return self::$enableEncryption; 110 | } 111 | 112 | public static function setEnableEncryption($enableEncryption) 113 | { 114 | if ( ! is_bool($enableEncryption)) { 115 | throw new Exception('TextRazor Error: enableEncryption must be a bool'); 116 | } 117 | 118 | self::$enableEncryption = $enableEncryption; 119 | } 120 | 121 | /** 122 | * Sets the connection phase timeout in seconds, or 0 for the default. 123 | * See https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html for details. 124 | * 125 | * This timeout will not interrupt TextRazor's analysis process, which has a timeout of its own of 30 seconds. 126 | */ 127 | public static function setConnectTimeoutSeconds($connectTimeoutSeconds) 128 | { 129 | self::$connectTimeoutSeconds = $connectTimeoutSeconds; 130 | } 131 | 132 | public static function getConnectTimeoutSeconds() 133 | { 134 | return self::$connectTimeoutSeconds; 135 | } 136 | 137 | /** 138 | * Sets the data transfer timeout in seconds, or 0 for the default. 139 | * See https://curl.se/libcurl/c/CURLOPT_TIMEOUT.html for details. 140 | * 141 | * This timeout will not interrupt TextRazor's analysis process, which has a timeout of its own of 30 seconds. 142 | */ 143 | public static function setTimeoutSeconds($timeoutSeconds) 144 | { 145 | self::$timeoutSeconds = $timeoutSeconds; 146 | } 147 | 148 | public static function getTimeoutSeconds() 149 | { 150 | return self::$timeoutSeconds; 151 | } 152 | } 153 | 154 | class TextRazorConnection 155 | { 156 | private $apiKey; 157 | 158 | private $endPoint; 159 | 160 | private $secureEndPoint; 161 | 162 | private $enableEncryption; 163 | 164 | private $enableCompression; 165 | 166 | private $timeoutSeconds; 167 | 168 | private $connectTimeoutSeconds; 169 | 170 | public function __construct($apiKey) 171 | { 172 | $this->apiKey = TextRazorSettings::getApiKey(); 173 | $this->endPoint = TextRazorSettings::getEndPoint(); 174 | $this->secureEndPoint = TextRazorSettings::getSecureEndpoint(); 175 | $this->enableEncryption = TextRazorSettings::getEnableEncryption(); 176 | $this->enableCompression = TextRazorSettings::getEnableCompression(); 177 | $this->timeoutSeconds = TextRazorSettings::getTimeoutSeconds(); 178 | $this->connectTimeoutSeconds = TextRazorSettings::getConnectTimeoutSeconds(); 179 | 180 | if (isset($apiKey)) { 181 | $this->apiKey = $apiKey; 182 | } 183 | 184 | if ( ! is_string($this->apiKey)) { 185 | throw new Exception('TextRazor Error: Invalid API key'); 186 | } 187 | 188 | if ( ! function_exists('curl_version')) { 189 | throw new Exception('TextRazor Error: TextRazor requires cURL support to be enabled on your PHP installation'); 190 | } 191 | } 192 | 193 | public function setAPIKey($apiKey) 194 | { 195 | if ( ! is_string($apiKey)) { 196 | throw new Exception('TextRazor Error: Invalid API key'); 197 | } 198 | 199 | $this->apiKey = $apiKey; 200 | } 201 | 202 | public function setEndPoint($endPoint) 203 | { 204 | if ( ! is_string($endPoint)) { 205 | throw new Exception('TextRazor Error: Invalid HTTP Endpoint'); 206 | } 207 | 208 | $this->endPoint = $endPoint; 209 | } 210 | 211 | public function setSecureEndPoint($endPoint) 212 | { 213 | if ( ! is_string($endPoint)) { 214 | throw new Exception('TextRazor Error: Invalid HTTPS Endpoint'); 215 | } 216 | 217 | $this->secureEndPoint = $endPoint; 218 | } 219 | 220 | public function setConnectTimeoutSeconds($connectTimeoutSeconds) 221 | { 222 | $this->connectTimeoutSeconds = $connectTimeoutSeconds; 223 | } 224 | 225 | public function setTimeoutSeconds($timeoutSeconds) 226 | { 227 | $this->timeoutSeconds = $timeoutSeconds; 228 | } 229 | 230 | public function setEnableCompression($enableCompression) 231 | { 232 | if ( ! is_bool($enableCompression)) { 233 | throw new Exception('TextRazor Error: enableCompression must be a bool'); 234 | } 235 | 236 | $this->enableCompression = $enableCompression; 237 | } 238 | 239 | public function setEnableEncryption($enableEncryption) 240 | { 241 | if ( ! is_bool($enableEncryption)) { 242 | throw new Exception('TextRazor Error: enableEncryption must be a bool'); 243 | } 244 | 245 | $this->enableEncryption = $enableEncryption; 246 | } 247 | 248 | public function sendRequest($textrazorParams, $path = '', $method = 'POST', $contentType = null) 249 | { 250 | $curl = curl_init(); 251 | 252 | if ($this->enableEncryption) { 253 | curl_setopt($curl, CURLOPT_URL, $this->secureEndPoint . $path); 254 | } else { 255 | curl_setopt($curl, CURLOPT_URL, $this->endPoint . $path); 256 | } 257 | 258 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 259 | 260 | if ($this->enableCompression) { 261 | curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate'); 262 | } 263 | 264 | curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $this->connectTimeoutSeconds); 265 | curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeoutSeconds); 266 | 267 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); 268 | curl_setopt($curl, CURLOPT_POSTFIELDS, $textrazorParams); 269 | 270 | $headers = []; 271 | $headers[] = 'X-TextRazor-Key: ' . trim($this->apiKey); 272 | 273 | if ($contentType) { 274 | $headers[] = 'Content-Type: ' . $contentType; 275 | } 276 | 277 | curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); 278 | 279 | $reply = curl_exec($curl); 280 | 281 | $curlError = curl_errno($curl); 282 | if (0 != $curlError) { 283 | throw new Exception('TextRazor Error: Network problem connecting to TextRazor. CURL Error Code:' . $curlError); 284 | } 285 | 286 | $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE); 287 | if (200 != $httpStatus) { 288 | throw new Exception('TextRazor Error: TextRazor returned HTTP code: ' . $httpStatus . ' Message:' . $reply); 289 | } 290 | 291 | curl_close($curl); 292 | unset($curl); 293 | 294 | $jsonReply = json_decode($reply, true); 295 | 296 | return $jsonReply; 297 | } 298 | } 299 | 300 | class TextRazor extends TextRazorConnection 301 | { 302 | private $extractors = []; 303 | 304 | private $rules = null; 305 | 306 | private $cleanupHTML = false; 307 | 308 | private $languageOverride = null; 309 | 310 | private $dbpediaTypeFilters = []; 311 | 312 | private $freebaseTypeFilters = []; 313 | 314 | private $enrichmentQueries = []; 315 | 316 | private $allowOverlap = true; 317 | 318 | private $entityDictionaries = []; 319 | 320 | private $cleanupMode = null; 321 | 322 | private $cleanupReturnCleaned = false; 323 | 324 | private $cleanupReturnRaw = false; 325 | 326 | private $cleanupUseMetadata = false; 327 | 328 | private $downloadUserAgent = null; 329 | 330 | private $classifiers = []; 331 | 332 | private $classifierMaxCategories = null; 333 | 334 | public function __construct($apiKey = null) 335 | { 336 | parent::__construct($apiKey); 337 | } 338 | 339 | public function setExtractors($extractors) 340 | { 341 | if ( ! is_array($extractors)) { 342 | throw new Exception('TextRazor Error: extractors must be an array of strings'); 343 | } 344 | 345 | $this->extractors = $extractors; 346 | } 347 | 348 | public function addExtractor($extractor) 349 | { 350 | if ( ! is_string($extractor)) { 351 | throw new Exception('TextRazor Error: extractor must be a string'); 352 | } 353 | 354 | array_push($this->extractors, $extractor); 355 | } 356 | 357 | public function setClassifiers($classifiers) 358 | { 359 | if ( ! is_array($classifiers)) { 360 | throw new Exception('TextRazor Error: $classifiers must be an array of strings'); 361 | } 362 | 363 | $this->classifiers = $classifiers; 364 | } 365 | 366 | public function addClassifier($classifier) 367 | { 368 | if ( ! is_string($classifier)) { 369 | throw new Exception('TextRazor Error: $classifier must be a string'); 370 | } 371 | 372 | array_push($this->classifiers, $classifier); 373 | } 374 | 375 | public function setRules($rules) 376 | { 377 | if ( ! is_string($rules)) { 378 | throw new Exception('TextRazor Error: rules must be a string'); 379 | } 380 | 381 | $this->rules = $rules; 382 | } 383 | 384 | public function setCleanupHTML($cleanupHTML) 385 | { 386 | if ( ! is_bool($cleanupHTML)) { 387 | throw new Exception('TextRazor Error: cleanupHTML must be a bool'); 388 | } 389 | 390 | $this->cleanupHTML = $cleanupHTML; 391 | } 392 | 393 | public function setLanguageOverride($languageOverride) 394 | { 395 | if ( ! is_string($languageOverride)) { 396 | throw new Exception('TextRazor Error: languageOverride must be a string'); 397 | } 398 | 399 | $this->languageOverride = $languageOverride; 400 | } 401 | 402 | public function setAllowOverlap($allowOverlap) 403 | { 404 | if ( ! is_bool($allowOverlap)) { 405 | throw new Exception('TextRazor Error: allowOverlap must be a bool'); 406 | } 407 | 408 | $this->allowOverlap = $allowOverlap; 409 | } 410 | 411 | public function addEntityDictionary($dictionaryId) 412 | { 413 | if ( ! is_string($dictionaryId)) { 414 | throw new Exception('TextRazor Error: dictionaryId must be a string'); 415 | } 416 | 417 | array_push($this->entityDictionaries, $dictionaryId); 418 | } 419 | 420 | public function addDbpediaTypeFilter($filter) 421 | { 422 | if ( ! is_string($filter)) { 423 | throw new Exception('TextRazor Error: filter must be a string'); 424 | } 425 | 426 | array_push($this->dbpediaTypeFilters, $filter); 427 | } 428 | 429 | public function addFreebaseTypeFilter($filter) 430 | { 431 | if ( ! is_string($filter)) { 432 | throw new Exception('TextRazor Error: filter must be a string'); 433 | } 434 | 435 | array_push($this->freebaseTypeFilters, $filter); 436 | } 437 | 438 | public function addEnrichmentQuery($query) 439 | { 440 | if ( ! is_string($query)) { 441 | throw new Exception('TextRazor Error: query must be a string'); 442 | } 443 | 444 | array_push($this->enrichmentQueries, $query); 445 | } 446 | 447 | public function setCleanupMode($cleanupMode) 448 | { 449 | if ( ! is_string($cleanupMode)) { 450 | throw new Exception('TextRazor Error: Invalid Cleanup Mode'); 451 | } 452 | 453 | $this->cleanupMode = $cleanupMode; 454 | } 455 | 456 | public function setCleanupReturnCleaned($cleanupReturnCleaned) 457 | { 458 | if ( ! is_bool($cleanupReturnCleaned)) { 459 | throw new Exception('TextRazor Error: cleanupReturnCleaned must be a bool'); 460 | } 461 | 462 | $this->cleanupReturnCleaned = $cleanupReturnCleaned; 463 | } 464 | 465 | public function setCleanupReturnRaw($cleanupReturnRaw) 466 | { 467 | if ( ! is_bool($cleanupReturnRaw)) { 468 | throw new Exception('TextRazor Error: cleanupReturnRaw must be a bool'); 469 | } 470 | 471 | $this->cleanupReturnRaw = $cleanupReturnRaw; 472 | } 473 | 474 | public function setCleanupUseMetadata($cleanupUseMetadata) 475 | { 476 | if ( ! is_bool($cleanupUseMetadata)) { 477 | throw new Exception('TextRazor Error: cleanupUseMetadata must be a bool'); 478 | } 479 | 480 | $this->cleanupUseMetadata = $cleanupUseMetadata; 481 | } 482 | 483 | public function setDownloadUserAgent($downloadUserAgent) 484 | { 485 | if ( ! is_string($downloadUserAgent)) { 486 | throw new Exception('TextRazor Error: Invalid downloadUserAgent'); 487 | } 488 | 489 | $this->downloadUserAgent = $downloadUserAgent; 490 | } 491 | 492 | public function setClassifierMaxCategories($classifierMaxCategories) 493 | { 494 | $this->classifierMaxCategories = $classifierMaxCategories; 495 | } 496 | 497 | public function analyzeUrl($url) 498 | { 499 | if ( ! is_string($url)) { 500 | throw new Exception('TextRazor Error: url must be a UTF8 encoded string'); 501 | } 502 | 503 | $builder = $this->buildRequest(); 504 | $builder->add('url', $url); 505 | 506 | return $this->sendRequest($builder->build()); 507 | } 508 | 509 | private function buildRequest() 510 | { 511 | $builder = new TextRazorQueryBuilder(); 512 | 513 | $builder->add('extractors', $this->extractors); 514 | $builder->add('cleanupHTML', $this->cleanupHTML); 515 | $builder->add('extractors', $this->extractors); 516 | $builder->add('rules', $this->rules); 517 | $builder->add('languageOverride', $this->languageOverride); 518 | 519 | $builder->add('entities.allowOverlap', $this->allowOverlap); 520 | $builder->add('entities.filterDbpediaTypes', $this->dbpediaTypeFilters); 521 | $builder->add('entities.filterFreebaseTypes', $this->freebaseTypeFilters); 522 | $builder->add('entities.enrichmentQueries', $this->enrichmentQueries); 523 | $builder->add('entities.dictionaries', $this->entityDictionaries); 524 | 525 | $builder->add('classifiers', $this->classifiers); 526 | $builder->add('classifier.maxCategories', $this->classifierMaxCategories); 527 | 528 | $builder->add('cleanup.mode', $this->cleanupMode); 529 | $builder->add('cleanup.returnCleaned', $this->cleanupReturnCleaned); 530 | $builder->add('cleanup.returnRaw', $this->cleanupReturnRaw); 531 | $builder->add('cleanup.useMetadata', $this->cleanupUseMetadata); 532 | 533 | $builder->add('download.userAgent', $this->downloadUserAgent); 534 | 535 | return $builder; 536 | } 537 | 538 | public function analyze($text) 539 | { 540 | if ( ! is_string($text)) { 541 | throw new Exception('TextRazor Error: text must be a UTF8 encoded string'); 542 | } 543 | 544 | $builder = $this->buildRequest(); 545 | $builder->add('text', $text); 546 | 547 | return $this->sendRequest($builder->build()); 548 | } 549 | } 550 | 551 | class DictionaryManager extends TextRazorConnection 552 | { 553 | public function __construct($apiKey = null) 554 | { 555 | parent::__construct($apiKey); 556 | } 557 | 558 | /** 559 | * Creates a new dictionary using properties provided in the dict $dictionaryProperties. 560 | * See the properties of class Dictionary for valid options. 561 | * 562 | * @param $entityId 563 | * @param null $matchType 564 | * @param null $caseInsensitive 565 | * @param null $language 566 | * 567 | * @return mixed 568 | * @throws \Exception 569 | */ 570 | public function createDictionary($entityId, $matchType = null, $caseInsensitive = null, $language = null) 571 | { 572 | $request = []; 573 | 574 | if ( ! is_string($entityId)) { 575 | throw new Exception('TextRazor Error: Custom Entity Dictionaries must have an ID.'); 576 | } 577 | 578 | if (isset($matchType)) { 579 | $request['matchType'] = $matchType; 580 | } 581 | if (isset($caseInsensitive)) { 582 | $request['caseInsensitive'] = $caseInsensitive; 583 | } 584 | if (isset($language)) { 585 | $request['language'] = $language; 586 | } 587 | 588 | $encodedRequest = empty($request) ? '{}' : json_encode($request); 589 | 590 | return $this->sendRequest($encodedRequest, '/entities/' . $entityId, 'PUT'); 591 | } 592 | 593 | public function allDictionaries() 594 | { 595 | return $this->sendRequest('', '/entities/', 'GET'); 596 | } 597 | 598 | public function deleteDictionary($entityId) 599 | { 600 | if ( ! is_string($entityId)) { 601 | throw new Exception('TextRazor Error: Custom Entity Dictionaries must have an ID.'); 602 | } 603 | 604 | return $this->sendRequest('', '/entities/' . $entityId, 'DELETE'); 605 | } 606 | 607 | public function getDictionary($entityId) 608 | { 609 | if ( ! is_string($entityId)) { 610 | throw new Exception('TextRazor Error: Custom Entity Dictionaries must have an ID.'); 611 | } 612 | 613 | return $this->sendRequest('', '/entities/' . $entityId, 'GET'); 614 | } 615 | 616 | public function allEntries($entityId, $limit = null, $offset = null) 617 | { 618 | if ( ! is_string($entityId)) { 619 | throw new Exception('TextRazor Error: Custom Entity Dictionaries must have an ID.'); 620 | } 621 | 622 | $urlParams = []; 623 | 624 | if (isset($limit)) { 625 | $urlParams['limit'] = $limit; 626 | } 627 | 628 | if (isset($offset)) { 629 | $urlParams['offset'] = $offset; 630 | } 631 | 632 | return $this->sendRequest('', '/entities/' . $entityId . '/_all?' . http_build_query($urlParams), 'GET'); 633 | } 634 | 635 | public function addEntries($entityId, $entries) 636 | { 637 | if ( ! is_array($entries)) { 638 | throw new Exception('TextRazor Error: Entries must be a List of dicts corresponding to properties of the new DictionaryEntry objects.'); 639 | } 640 | 641 | if (empty($entries)) { 642 | throw new Exception('TextRazor Error: Array of new entries cannot be empty.'); 643 | } 644 | 645 | return $this->sendRequest(json_encode($entries), '/entities/' . $entityId . '/', 'POST'); 646 | } 647 | 648 | public function getEntry($dictionaryId, $entryId) 649 | { 650 | if ( ! is_string($dictionaryId)) { 651 | throw new Exception('TextRazor Error: Custom Entity Dictionaries must have an ID.'); 652 | } 653 | 654 | if ( ! is_string($entryId)) { 655 | throw new Exception('TextRazor Error: Custom Entity Dictionary Entries can only be retrieved by ID.'); 656 | } 657 | 658 | return $this->sendRequest('', '/entities/' . $dictionaryId . '/' . $entryId, 'GET'); 659 | } 660 | 661 | public function deleteEntry($dictionaryId, $entryId) 662 | { 663 | if ( ! is_string($dictionaryId)) { 664 | throw new Exception('TextRazor Error: Custom Entity Dictionaries must have an ID.'); 665 | } 666 | 667 | if ( ! is_string($entryId)) { 668 | throw new Exception('TextRazor Error: Custom Entity Dictionary Entries can only be deleted by ID.'); 669 | } 670 | 671 | return $this->sendRequest('', '/entities/' . $dictionaryId . '/' . $entryId, 'DELETE'); 672 | } 673 | } 674 | 675 | class ClassifierManager extends TextRazorConnection 676 | { 677 | public function __construct($apiKey = null) 678 | { 679 | parent::__construct($apiKey); 680 | } 681 | 682 | public function createClassifier($classifierID, $categories) 683 | { 684 | if ( ! is_string($classifierID)) { 685 | throw new Exception('TextRazor Error: Classifiers must have an ID.'); 686 | } 687 | 688 | if ( ! is_array($categories)) { 689 | throw new Exception('TextRazor Error: $categories must be a List of dicts corresponding to properties of the new Category objects.'); 690 | } 691 | 692 | if (empty($categories)) { 693 | throw new Exception('TextRazor Error: Array of new categories cannot be empty.'); 694 | } 695 | 696 | return $this->sendRequest(json_encode($categories), '/categories/' . $classifierID, 'PUT', 'application/json'); 697 | } 698 | 699 | public function createClassifierWithCSV($classifierID, $categoriesCSV) 700 | { 701 | if ( ! is_string($classifierID)) { 702 | throw new Exception('TextRazor Error: Classifiers must have an ID.'); 703 | } 704 | 705 | if ( ! is_string($categoriesCSV)) { 706 | throw new Exception('TextRazor Error: $categoriesCSV must be a String containing the contents of a csv file that defines a new classifier.'); 707 | } 708 | 709 | return $this->sendRequest($categoriesCSV, '/categories/' . $classifierID, 'PUT', 'application/csv'); 710 | } 711 | 712 | public function deleteClassifier($classifierID) 713 | { 714 | return $this->sendRequest('', '/categories/' . $classifierID, 'DELETE'); 715 | } 716 | 717 | public function allCategories($classifierID, $limit = null, $offset = null) 718 | { 719 | if ( ! is_string($classifierID)) { 720 | throw new Exception('TextRazor Error: Classifiers must have an ID.'); 721 | } 722 | 723 | $urlParams = []; 724 | 725 | if (isset($limit)) { 726 | $urlParams['limit'] = $limit; 727 | } 728 | 729 | if (isset($offset)) { 730 | $urlParams['offset'] = $offset; 731 | } 732 | 733 | return $this->sendRequest('', '/categories/' . $classifierID . '/_all?' . http_build_query($urlParams), 'GET'); 734 | } 735 | 736 | public function deleteCategory($classifierID, $categoryID) 737 | { 738 | return $this->sendRequest('', '/categories/' . $classifierID . '/' . $categoryID, 'DELETE'); 739 | } 740 | 741 | public function getCategory($classifierID, $categoryID) 742 | { 743 | return $this->sendRequest('', '/categories/' . $classifierID . '/' . $categoryID, 'GET'); 744 | } 745 | } 746 | 747 | class AccountManager extends TextRazorConnection 748 | { 749 | public function __construct($apiKey = null) 750 | { 751 | parent::__construct($apiKey); 752 | } 753 | 754 | public function getAccount() 755 | { 756 | return $this->sendRequest('', '/account/', 'GET'); 757 | } 758 | } 759 | --------------------------------------------------------------------------------