Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['8.1', '8.2', '8.3', '8.4']
php-versions: ['8.1', '8.2', '8.3', '8.4', '8.5']
fail-fast: false

name: PHP ${{ matrix.php-versions }} Test
Expand All @@ -29,7 +29,7 @@ jobs:
php-version: ${{ matrix.php-versions }}
tools: composer:v2
coverage: xdebug
continue-on-error: ${{ matrix.php-versions == '8.4' }}
continue-on-error: ${{ matrix.php-versions == '8.5' }}

- name: Validate composer.json and composer.lock
run: composer validate --strict
Expand Down
8 changes: 4 additions & 4 deletions src/Chart.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __construct()
/**
* Get the chart as an array
*
* @return array
* @return array<string, mixed>
*/
public function get(): array
{
Expand All @@ -35,7 +35,7 @@ public function get(): array
/**
* Convert the chart to an array
*
* @return array
* @return array<string, mixed>
*/
public function toArray(): array
{
Expand Down Expand Up @@ -107,10 +107,10 @@ public function beginAtZero(): self
* Generate the HTML representation of the chart
*
* @param string $element
* @param Chart $chart
* @param Chart|null $chart
* @return string
*/
public function toHtml(string $element, Chart $chart = null): string
public function toHtml(string $element, ?Chart $chart = null): string
{
if ($chart === null) {
$chart = $this;
Expand Down
6 changes: 6 additions & 0 deletions src/ChartInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@

interface ChartInterface
{
/**
* @return array<string, mixed>
*/
public function get(): array;

public function toJson(): string;

/**
* @return array<string, mixed>
*/
public function toArray(): array;
}
39 changes: 31 additions & 8 deletions src/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@

class Config implements ConfigInterface
{
/**
* @var array<string, mixed>
*/
protected array $attributes;

/**
* @param array<string, mixed> $attributes
*/
public function __construct(array $attributes = [])
{
$this->attributes = $attributes;
Expand All @@ -27,40 +33,57 @@ public function &__get($name)
*
* @param string $name
* @param mixed $value
* @return $this
* @return void
*/
public function &__set($name, $value)
public function __set($name, $value)
{
$this->attributes[$name] = $value;

return $this;
}

/**
* Dynamically set the value of a property.
*
* @param string $name
* @param mixed $value
* @param array<int, mixed> $value
* @return $this
*/
public function __call($name, $value)
{
return $this->__set($name, reset($value));
$this->__set($name, reset($value));

return $this;
}

/**
* Convert the object to an array.
*
* @return array
* @return array<string, mixed>
*/
public function toArray(): array
{
array_walk_recursive($this->attributes, function (&$item) {
if (is_object($item)) {
if (is_object($item) && method_exists($item, 'toArray')) {
$item = $item->toArray();
}
});

return $this->attributes;
}

/**
* @return array<string, mixed>
*/
public function get(): array
{
return $this->toArray();
}

/**
* @return string
* @throws \JsonException
*/
public function toJson(): string
{
return json_encode($this->toArray(), JSON_THROW_ON_ERROR | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
}
}
10 changes: 10 additions & 0 deletions src/Config/ConfigInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,15 @@

interface ConfigInterface
{
/**
* @return array<string, mixed>
*/
public function get(): array;

public function toJson(): string;

/**
* @return array<string, mixed>
*/
public function toArray(): array;
}
3 changes: 3 additions & 0 deletions src/Config/Options.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Bbsnly\ChartJs\Config;

/**
* @method self scales(array<string, mixed> $value)
*/
class Options extends Config
{

Expand Down
39 changes: 39 additions & 0 deletions tests/ChartTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -526,4 +526,43 @@ private function assertStringNotContains(string $needle, string $haystack): void
"Failed asserting that '$haystack' does not contain '$needle'"
);
}
/**
* Test if Config class get() and toJson() methods work correctly
*/
public function test_config_get_and_tojson_methods()
{
$config = new \Bbsnly\ChartJs\Config\Config(['key' => 'value']);

$this->assertEquals(['key' => 'value'], $config->get());
$this->assertEquals('{"key":"value"}', $config->toJson());
}

/**
* Regression test for issue #34: `$data->datasets[] = ...; PHP error`.
*
* Appending to a not-yet-existing magic property must mutate the real
* underlying array. This relies on Config::&__get() returning the
* attribute by reference. Without it PHP raises
* "Indirect modification of overloaded property ... has no effect"
* (which PHPUnit turns into a failure) and the append is silently lost.
*/
public function test_it_can_append_to_a_magic_array_property()
{
$data = new Data();

// Property does not exist yet — append must create and grow the array.
$data->datasets[] = (new Dataset)->data([10, 20, 30]);
$data->datasets[] = (new Dataset)->data([30, 20, 10]);

$this->assertCount(2, $data->datasets);
$this->assertEquals(
[
'datasets' => [
['data' => [10, 20, 30]],
['data' => [30, 20, 10]],
],
],
$data->toArray()
);
}
}
Loading