Skip to content

Commit

Permalink
Container, BaseControl: extension methods are implemented independent…
Browse files Browse the repository at this point in the history
…ly on ObjectMixin
  • Loading branch information
dg committed Feb 2, 2017
1 parent 085804c commit a8c2e65
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 6 deletions.
12 changes: 9 additions & 3 deletions src/Forms/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
*/
class Container extends Nette\ComponentModel\Container implements \ArrayAccess
{
/** @var callable[] extension methods */
private static $extMethods = [];

/** @var callable[] function (Container $sender); Occurs when the form is validated */
public $onValidate;

Expand Down Expand Up @@ -410,19 +413,22 @@ public function addContainer($name): self

public function __call(string $name, array $args)
{
if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(__CLASS__, $name)) {
if (isset(self::$extMethods[$name])) {
return (self::$extMethods[$name])($this, ...$args);
} elseif ($callback = Nette\Utils\ObjectMixin::getExtensionMethod($class = __CLASS__, $name)) {
trigger_error("Define extension method '$name' via $class::extensionMethod('$name', ...), don't use Nette\\Object or Nette\\Utils\\ObjectMixin.", E_USER_DEPRECATED);
return Nette\Utils\Callback::invoke($callback, $this, ...$args);
}
return parent::__call($name, $args);
}


public static function extensionMethod($name, /*callable*/ $callback = NULL): void
public static function extensionMethod($name, /*callable*/ $callback): void
{
if (strpos($name, '::') !== FALSE) { // back compatibility
[, $name] = explode('::', $name);
}
Nette\Utils\ObjectMixin::setExtensionMethod(__CLASS__, $name, $callback);
self::$extMethods[$name] = $callback;
}


Expand Down
18 changes: 15 additions & 3 deletions src/Forms/Controls/BaseControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ abstract class BaseControl extends Nette\ComponentModel\Component implements ICo
/** @var string */
public static $idMask = 'frm-%s';

/** @var callable[][] extension methods */
private static $extMethods = [];

/** @var string|object textual caption or label */
public $caption;

Expand Down Expand Up @@ -556,19 +559,28 @@ public function getOptions(): array

public function __call(string $name, array $args)
{
if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod(get_class($this), $name)) {
$class = static::class;
do {
if (isset(self::$extMethods[$name][$class])) {
return (self::$extMethods[$name][$class])($this, ...$args);
}
$class = get_parent_class($class);
} while ($class);

if ($callback = Nette\Utils\ObjectMixin::getExtensionMethod($class = static::class, $name)) {
trigger_error("Define extension method '$name' via $class::extensionMethod('$name', ...), don't use Nette\\Object or Nette\\Utils\\ObjectMixin.", E_USER_DEPRECATED);
return Nette\Utils\Callback::invoke($callback, $this, ...$args);
}
return parent::__call($name, $args);
}


public static function extensionMethod(string $name, /*callable*/ $callback = NULL): void
public static function extensionMethod($name, /*callable*/ $callback): void
{
if (strpos($name, '::') !== FALSE) { // back compatibility
[, $name] = explode('::', $name);
}
Nette\Utils\ObjectMixin::setExtensionMethod(get_called_class(), $name, $callback);
self::$extMethods[$name][static::class] = $callback;
}

}
38 changes: 38 additions & 0 deletions tests/Forms/BaseControl.extensionMethod.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

use Nette\Forms\Controls\TextBase;
use Nette\Forms\Controls\TextInput;
use Nette\Forms\Controls\Checkbox;
use Nette\Forms\Controls\Button;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


TextBase::extensionMethod('test', function ($control, $a, $b) {
Assert::type(TextInput::class, $control);
Assert::same(1, $a);
Assert::same(2, $b);
return 'TextInput';
});

Checkbox::extensionMethod('test', function ($control, $a, $b) {
Assert::type(Checkbox::class, $control);
Assert::same(1, $a);
Assert::same(2, $b);
return 'Checkbox';
});

$control1 = new TextInput;
Assert::same('TextInput', $control1->test(1, 2));

$control2 = new Checkbox;
Assert::same('Checkbox', $control2->test(1, 2));

Assert::exception(function () {
$control3 = new Button;
$control3->test(1, 2);
}, Nette\MemberAccessException::class);
20 changes: 20 additions & 0 deletions tests/Forms/Container.extensionMethod.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

use Nette\Forms\Form;
use Tester\Assert;


require __DIR__ . '/../bootstrap.php';


Nette\Forms\Container::extensionMethod('test', function ($form, $a, $b) {
Assert::type(Nette\Forms\Form::class, $form);
Assert::same(1, $a);
Assert::same(2, $b);
return 3;
});

$form = new Form;
Assert::same(3, $form->test(1, 2));

0 comments on commit a8c2e65

Please sign in to comment.