Skip to content

Commit cc27395

Browse files
committed
2.0.0
1 parent d9cd04c commit cc27395

5 files changed

Lines changed: 61 additions & 12 deletions

File tree

.gitattributes

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/.github export-ignore
2+
/.gitattributes export-ignore
3+
/.gitignore export-ignore
4+
/.php-cs-fixer.php export-ignore
15
/examples export-ignore
26
/nbproject export-ignore
7+
/phpstan.neon export-ignore
8+
/phpunit.xml export-ignore
9+
/tests export-ignore
310
/tools export-ignore

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,25 @@ This version supports Ampache 6.2.0 and newer.
1414
* `api_format` selects `xml` or `json` responses
1515
* `server_version` selects the api version to talk to, defaulting to 6
1616
* `timeout` sets the per-request timeout in seconds
17-
* `api_secure` selects `https` or `http`
1817

1918
### Changed (2.0.0)
2019

2120
* `send_command()` returns a `SimpleXMLElement` or a decoded json array as the server sent it, replacing the structure 1.x assembled
2221
* Commands are checked against the api version in use, so a method that version does not serve is refused before the request is sent
2322
* `tag`, `tags`, `tag_albums`, `tag_artists` and `tag_songs` are refused from API5 onwards, and `get_indexes`, `playlist_add_song` and `user_update` from API8, matching the versions that dropped them
23+
* `api_secure` is consulted only when it is passed; otherwise the scheme on `server` selects `https` or `http`, and `https` remains the fallback when neither says
24+
* `__construct()` requires a config array, where 1.x defaulted it to an empty one
25+
* `debug_callback` receives `AmpacheApi\AmpacheApi/<version>` as its first argument in place of the bare `AmpacheApi` 1.x sent
26+
27+
### Removed (2.0.0)
28+
29+
* The public methods 1.x used to assemble its own response structure, made redundant by `send_command()` handing back the decoded response
30+
* `parse_response()`
31+
* `get_response()`
32+
* `XML_create_parser()`
33+
* `XML_cdata()`
34+
* `XML_start_element()`
35+
* `XML_end_element()`
2436

2537
### Fixed (2.0.0)
2638

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Ampache API PHP Library.
44

55
## NEWS
66

7-
Version 2 of this library is underway.
7+
Version 2 is out, and it is not a drop-in replacement for 1.x.
88

9-
There are major changes to help support multiple purposes as well as both XML and JSON responses.
10-
11-
The library will now return a SimpleXMLElement or a decoded JSON array instead of the frankenstein.
9+
`send_command()` returns a SimpleXMLElement or a decoded JSON array exactly as the server sent it, instead of the structure 1.x assembled, so `last_error()` is now how you tell a successful call from a failed one.
1210

1311
This version of the library is supported from Ampache 6.2.0+ and talks to API versions 3, 4, 5, 6 and 8. (Ampache has no API 7.)
1412

13+
See the [CHANGELOG](CHANGELOG.md) for everything that moved.
14+
1515
## License
1616

1717
Ampache API PHP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License v3 (AGPLv3) as published by the Free Software Foundation.
@@ -25,11 +25,11 @@ When creating an AmpacheApi object config is set using a config array.
2525
* Required
2626
* username: string - Your API username
2727
* password: string - Your API password, plain or already sha256 hashed
28-
* server: string - Server address; an `http://` or `https://` prefix is stripped, and `api_secure` decides which is used
28+
* server: string - Server address, with or without an `http://` or `https://` prefix
2929
* Optional
3030
* debug: bool - Enable debug mode which will echo debug messages (default: false)
3131
* debug_callback: callable - Function that receives debug messages; it is called whether or not `debug` is on (default: null)
32-
* api_secure: bool - Set to false to use http (default: true)
32+
* api_secure: bool - Set to false to use http; when omitted, a scheme on `server` decides and https is the fallback
3333
* api_format: string - Set API response format. xml, json (default: xml)
3434
* server_version: int - Set API response version. 3, 4, 5, 6, 8 (default: 6)
3535
* timeout: int - Per request timeout in seconds (default: PHP's `default_socket_timeout`)

src/AmpacheApi.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class AmpacheApi
5151
6 => '6.9.1',
5252
8 => '8.0.0',
5353
];
54-
private const LIB_VERSION = '2.0.0-develop';
54+
private const LIB_VERSION = '2.0.0';
5555

5656
/**
5757
* The api version each method was introduced in.
@@ -362,17 +362,24 @@ public function configure(array $config): bool
362362
$this->api_timeout = max(0, (int) $config['timeout']);
363363
}
364364

365+
$server = trim((string) $config['server']);
366+
$scheme = (preg_match('#^(https?)://#i', $server, $matches) === 1)
367+
? strtolower($matches[1])
368+
: '';
369+
365370
if (isset($config['api_secure'])) {
366371
// This should be a boolean response
367372
$this->api_secure = (bool) $config['api_secure'];
373+
} elseif ($scheme !== '') {
374+
// nothing was asked for, so an address that names its scheme is the only instruction we have
375+
$this->api_secure = ($scheme === 'https');
368376
}
369377
$protocol = $this->api_secure
370378
? 'https://'
371379
: 'http://';
372380

373381
// Strip whichever scheme the caller supplied; api_secure picks the one we use
374-
$server = (string) preg_replace('#^https?://#i', '', trim((string) $config['server']));
375-
$server = rtrim($server, '/');
382+
$server = rtrim((string) preg_replace('#^https?://#i', '', $server), '/');
376383
$this->api_url = $protocol . $server . '/server/' . $this->api_format . '.server.php';
377384

378385
// See if we have enough to authenticate, if so change the state
@@ -452,12 +459,15 @@ public function connect(): bool
452459
*/
453460
public function get_command_url(string $command, ?array $options = []): string
454461
{
462+
if ($this->state() != 'READY' && $this->state() != 'CONNECTED') {
463+
throw new Exception('AmpacheApi::get_command_url API in non-ready state, unable to build a url');
464+
}
455465
$command = trim($command);
456466
if (!$command) {
457-
throw new Exception('AmpacheApi::send_command no command specified');
467+
throw new Exception('AmpacheApi::get_command_url no command specified');
458468
}
459469
if (!$this->validate_command($command)) {
460-
throw new Exception('AmpacheApi::send_command Invalid/Unknown command ' . $command . ' issued');
470+
throw new Exception('AmpacheApi::get_command_url Invalid/Unknown command ' . $command . ' issued');
461471
}
462472

463473
$url = $this->api_url . '?action=' . urlencode($command);

tests/AmpacheApiTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,25 @@ public function testOptionsAreUrlEncoded(): void
172172
self::assertStringContainsString('&rule_1_input=a+b%26c', $url);
173173
}
174174

175+
public function testSchemeInTheServerAddressDecidesWhenApiSecureIsNotAsked(): void
176+
{
177+
$api = $this->configured(['server' => 'http://localhost:8080']);
178+
179+
self::assertStringStartsWith('http://localhost:8080/server/', $api->get_command_url('ping'));
180+
}
181+
175182
public function testSchemeInTheServerAddressIsReplacedByTheOneApiSecureAsksFor(): void
176183
{
177184
$api = $this->configured(['server' => 'http://music.example', 'api_secure' => true]);
178185

179186
self::assertStringStartsWith('https://music.example/server/', $api->get_command_url('ping'));
180187
}
181188

189+
public function testSchemelessAddressStaysOnHttps(): void
190+
{
191+
self::assertStringStartsWith('https://music.example/server/', $this->configured()->get_command_url('ping'));
192+
}
193+
182194
public function testStartsUnconfiguredAndBecomesReady(): void
183195
{
184196
$api = (new ReflectionClass(AmpacheApi::class))->newInstanceWithoutConstructor();
@@ -210,6 +222,14 @@ public function testUnknownCommandIsRefusedBeforeAnyRequest(): void
210222
$this->configured()->get_command_url('not_a_method');
211223
}
212224

225+
public function testUrlCannotBeBuiltBeforeTheClientIsConfigured(): void
226+
{
227+
$this->expectException(Exception::class);
228+
$this->expectExceptionMessage('non-ready state');
229+
230+
(new ReflectionClass(AmpacheApi::class))->newInstanceWithoutConstructor()->get_command_url('ping');
231+
}
232+
213233
public function testUrlUsesTheFormatAsTheEndpoint(): void
214234
{
215235
self::assertStringStartsWith(

0 commit comments

Comments
 (0)