diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 3455d6c..b32b4ec 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -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 @@ -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 diff --git a/src/Chart.php b/src/Chart.php index c4220d0..9d10c7b 100644 --- a/src/Chart.php +++ b/src/Chart.php @@ -25,7 +25,7 @@ public function __construct() /** * Get the chart as an array * - * @return array + * @return array */ public function get(): array { @@ -35,7 +35,7 @@ public function get(): array /** * Convert the chart to an array * - * @return array + * @return array */ public function toArray(): array { @@ -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; diff --git a/src/ChartInterface.php b/src/ChartInterface.php index f84ea52..d094f01 100644 --- a/src/ChartInterface.php +++ b/src/ChartInterface.php @@ -4,9 +4,15 @@ interface ChartInterface { + /** + * @return array + */ public function get(): array; public function toJson(): string; + /** + * @return array + */ public function toArray(): array; } diff --git a/src/Config/Config.php b/src/Config/Config.php index 2244799..5e00ed4 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -4,8 +4,14 @@ class Config implements ConfigInterface { + /** + * @var array + */ protected array $attributes; + /** + * @param array $attributes + */ public function __construct(array $attributes = []) { $this->attributes = $attributes; @@ -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 $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 */ 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 + */ + 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); + } } diff --git a/src/Config/ConfigInterface.php b/src/Config/ConfigInterface.php index 041e6a4..e877c2d 100644 --- a/src/Config/ConfigInterface.php +++ b/src/Config/ConfigInterface.php @@ -4,5 +4,15 @@ interface ConfigInterface { + /** + * @return array + */ + public function get(): array; + + public function toJson(): string; + + /** + * @return array + */ public function toArray(): array; } diff --git a/src/Config/Options.php b/src/Config/Options.php index 019e326..4797bb5 100644 --- a/src/Config/Options.php +++ b/src/Config/Options.php @@ -2,6 +2,9 @@ namespace Bbsnly\ChartJs\Config; +/** + * @method self scales(array $value) + */ class Options extends Config { diff --git a/tests/ChartTest.php b/tests/ChartTest.php index cd38ff6..8e5c85c 100644 --- a/tests/ChartTest.php +++ b/tests/ChartTest.php @@ -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() + ); + } }