New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.7] Throw error with proper message when dispatching dynamic method calls #25163

Merged
merged 2 commits into from Aug 12, 2018
Jump to file or symbol
Failed to load files and symbols.
+167 −33
Diff settings

Always

Just for now

@@ -8,6 +8,7 @@
use Illuminate\Support\Str;
use Illuminate\Pagination\Paginator;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Database\Concerns\BuildsQueries;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
@@ -17,7 +18,7 @@
*/
class Builder
{
use BuildsQueries, Concerns\QueriesRelationships;
use BuildsQueries, Concerns\QueriesRelationships, ForwardsCalls;
/**
* The base query builder instance.
@@ -1317,7 +1318,7 @@ public function __call($method, $parameters)
return $this->toBase()->{$method}(...$parameters);
}
$this->query->{$method}(...$parameters);
$this->forwardCallTo($this->query, $method, $parameters);
return $this;
}
@@ -1340,9 +1341,7 @@ public static function __callStatic($method, $parameters)
}
if (! isset(static::$macros[$method])) {
throw new BadMethodCallException(sprintf(
'Method %s::%s does not exist.', static::class, $method
));
$this->throwBadMethodCallException($method);
}
if (static::$macros[$method] instanceof Closure) {
@@ -9,6 +9,7 @@
use Illuminate\Support\Str;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Contracts\Routing\UrlRoutable;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Database\Eloquent\Relations\Pivot;
@@ -24,7 +25,8 @@
Concerns\HasRelationships,
Concerns\HasTimestamps,
Concerns\HidesAttributes,
Concerns\GuardsAttributes;
Concerns\GuardsAttributes,
ForwardsCalls;
/**
* The connection name for the model.
@@ -1598,7 +1600,7 @@ public function __call($method, $parameters)
return $this->$method(...$parameters);
}
return $this->newQuery()->$method(...$parameters);
return $this->forwardCallTo($this->newQuery(), $method, $parameters);
}
/**
@@ -9,13 +9,14 @@
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Traits\ForwardsCalls;
/**
* @mixin \Illuminate\Database\Eloquent\Builder
*/
abstract class Relation
{
use Macroable {
use ForwardsCalls, Macroable {
__call as macroCall;
}
@@ -366,7 +367,7 @@ public function __call($method, $parameters)
return $this->macroCall($method, $parameters);
}
$result = $this->query->{$method}(...$parameters);
$result = $this->forwardCallTo($this->query, $method, $parameters);
if ($result === $this->query) {
return $this;
@@ -4,7 +4,6 @@
use Closure;
use RuntimeException;
use BadMethodCallException;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
@@ -13,14 +12,15 @@
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Database\Concerns\BuildsQueries;
use Illuminate\Database\Query\Grammars\Grammar;
use Illuminate\Database\Query\Processors\Processor;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
class Builder
{
use BuildsQueries, Macroable {
use BuildsQueries, ForwardsCalls, Macroable {
__call as macroCall;
}
@@ -2813,8 +2813,6 @@ public function __call($method, $parameters)
return $this->dynamicWhere($method, $parameters);
}
throw new BadMethodCallException(sprintf(
'Method %s::%s does not exist.', static::class, $method
));
$this->throwBadMethodCallException($method);
}
}
@@ -4,13 +4,16 @@
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Contracts\Routing\UrlGenerator;
/**
* @mixin \Illuminate\Routing\Router
*/
class RouteServiceProvider extends ServiceProvider
{
use ForwardsCalls;
/**
* The controller namespace for the application.
*
@@ -94,8 +97,8 @@ public function register()
*/
public function __call($method, $parameters)
{
return call_user_func_array(
[$this->app->make(Router::class), $method], $parameters
return $this->forwardCallTo(
$this->app->make(Router::class), $method, $parameters
);
}
}
@@ -2,19 +2,19 @@
namespace Illuminate\Http;
use BadMethodCallException;
use Illuminate\Support\Str;
use Illuminate\Support\MessageBag;
use Illuminate\Support\ViewErrorBag;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Session\Store as SessionStore;
use Illuminate\Contracts\Support\MessageProvider;
use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse as BaseRedirectResponse;
class RedirectResponse extends BaseRedirectResponse
{
use ResponseTrait, Macroable {
use ForwardsCalls, ResponseTrait, Macroable {
Macroable::__call as macroCall;
}
@@ -231,8 +231,6 @@ public function __call($method, $parameters)
return $this->with(Str::snake(substr($method, 4)), $parameters[0]);
}
throw new BadMethodCallException(sprintf(
'Method %s::%s does not exist.', static::class, $method
));
$this->throwBadMethodCallException($method);
}
}
@@ -3,9 +3,12 @@
namespace Illuminate\Http\Resources;
use Exception;
use Illuminate\Support\Traits\ForwardsCalls;
trait DelegatesToResource
{
use ForwardsCalls;
/**
* Get the value of the resource's route key.
*
@@ -125,6 +128,6 @@ public function __get($key)
*/
public function __call($method, $parameters)
{
return $this->resource->{$method}(...$parameters);
return $this->forwardCallTo($this->resource, $method, $parameters);
}
}
@@ -4,21 +4,21 @@
use ReflectionClass;
use ReflectionProperty;
use BadMethodCallException;
use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Illuminate\Support\HtmlString;
use Illuminate\Container\Container;
use Illuminate\Support\Traits\Localizable;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Support\Traits\ForwardsCalls;
use Illuminate\Contracts\Queue\Factory as Queue;
use Illuminate\Contracts\Mail\Mailer as MailerContract;
use Illuminate\Contracts\Mail\Mailable as MailableContract;
use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory;
class Mailable implements MailableContract, Renderable
{
use Localizable;
use ForwardsCalls, Localizable;
/**
* The locale of the message.
@@ -808,8 +808,6 @@ public function __call($method, $parameters)
return $this->with(Str::camel(substr($method, 4)), $parameters[0]);
}
throw new BadMethodCallException(sprintf(
'Method %s::%s does not exist.', static::class, $method
));
$this->throwBadMethodCallException($method);
}
}
@@ -4,12 +4,15 @@
use Swift_Image;
use Swift_Attachment;
use Illuminate\Support\Traits\ForwardsCalls;
/**
* @mixin \Swift_Message
*/
class Message
{
use ForwardsCalls;
/**
* The Swift Message instance.
*
@@ -321,8 +324,6 @@ public function getSwiftMessage()
*/
public function __call($method, $parameters)
{
$callable = [$this->swift, $method];
return call_user_func_array($callable, $parameters);
return $this->forwardCallTo($this->swift, $method, $parameters);
}
}
@@ -7,12 +7,15 @@
use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Support\Traits\ForwardsCalls;
/**
* @mixin \Illuminate\Support\Collection
*/
abstract class AbstractPaginator implements Htmlable
{
use ForwardsCalls;
/**
* All of the items being paginated.
*
@@ -620,7 +623,7 @@ public function toHtml()
*/
public function __call($method, $parameters)
{
return $this->getCollection()->$method(...$parameters);
return $this->forwardCallTo($this->getCollection(), $method, $parameters);
}
/**
@@ -0,0 +1,35 @@
<?php
namespace Illuminate\Support\Traits;
use Error;
use BadMethodCallException;
trait ForwardsCalls
{
protected function forwardCallTo($object, $method, $parameters)
{
try {
return $object->{$method}(...$parameters);
} catch (Error | BadMethodCallException $e) {
$pattern = '~^Call to undefined method (?P<class>[^:]+)::(?P<method>[a-zA-Z]+)\(\)$~';
if (! preg_match($pattern, $e->getMessage(), $matches)) {
throw $e;
}
if ($matches['class'] != get_class($object) || $matches['method'] != $method) {
throw $e;
}
$this->throwBadMethodCallException($method);
}
}
protected function throwBadMethodCallException($method)
{
throw new BadMethodCallException(sprintf(
'Call to undefined method %s::%s()', static::class, $method
));
}
}
@@ -121,7 +121,7 @@ public function testMagicCall()
/**
* @expectedException \BadMethodCallException
* @expectedExceptionMessage Method Illuminate\Http\RedirectResponse::doesNotExist does not exist.
* @expectedExceptionMessage Call to undefined method Illuminate\Http\RedirectResponse::doesNotExist()
*/
public function testMagicCallException()
{
@@ -189,7 +189,7 @@ public function testMagicCall()
/**
* @expectedException \BadMethodCallException
* @expectedExceptionMessage Method Illuminate\Http\RedirectResponse::doesNotExist does not exist.
* @expectedExceptionMessage Call to undefined method Illuminate\Http\RedirectResponse::doesNotExist()
*/
public function testMagicCallException()
{
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.