forked from jarektkaczyk/eloquence
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e702781
commit 108754a
Showing
10 changed files
with
415 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php namespace Sofa\Eloquence\Contracts; | ||
|
||
interface Mutator | ||
{ | ||
/** | ||
* Mutate value using provided methods. | ||
* | ||
* @param mixed $value | ||
* @param string|array $callable | ||
* @return mixed | ||
* | ||
* @throws \LogicException | ||
*/ | ||
public function mutate($value, $mutators); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?php namespace Sofa\Eloquence\Mutator; | ||
|
||
class InvalidCallableException extends \LogicException | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
<?php namespace Sofa\Eloquence\Mutator; | ||
|
||
use ReflectionException; | ||
use ReflectionClass; | ||
use ReflectionMethod; | ||
use Illuminate\Support\Traits\Macroable; | ||
use Sofa\Eloquence\Contracts\Mutator as MutatorContract; | ||
|
||
class Mutator implements MutatorContract | ||
{ | ||
use Macroable; | ||
|
||
/** | ||
* @inheritdoc | ||
*/ | ||
public function mutate($value, $callables) | ||
{ | ||
if (!is_array($callables)) { | ||
$callables = explode('|', $callables); | ||
} | ||
|
||
foreach ($callables as $callable) { | ||
list($callable, $args) = $this->parse(trim($callable)); | ||
|
||
$value = call_user_func_array($callable, array_merge([$value], $args)); | ||
} | ||
|
||
return $value; | ||
} | ||
|
||
/** | ||
* Parse provided mutator functions. | ||
* | ||
* @param string $callable | ||
* @return array | ||
* | ||
* @throws \Sofa\Eloquence\Mutator\InvalidCallableException | ||
*/ | ||
protected function parse($callable) | ||
{ | ||
list($callable, $args) = $this->parseArgs($callable); | ||
|
||
if ($this->isClassMethod($callable)) { | ||
$callable = $this->parseClassMethod($callable); | ||
|
||
} elseif ($this->isMutatorMethod($callable)) { | ||
$callable = [$this, $callable]; | ||
|
||
} elseif (!function_exists($callable)) { | ||
throw new InvalidCallableException("Function [{$callable}] not found."); | ||
} | ||
|
||
return [$callable, $args]; | ||
} | ||
|
||
/** | ||
* Determine whether callable is a class method. | ||
* | ||
* @param string $callable | ||
* @return boolean | ||
*/ | ||
protected function isClassMethod($callable) | ||
{ | ||
return strpos($callable, '@') !== false; | ||
} | ||
|
||
/** | ||
* Determine whether callable is available on this instance. | ||
* | ||
* @param string $callable | ||
* @return boolean | ||
*/ | ||
protected function isMutatorMethod($callable) | ||
{ | ||
return method_exists($this, $callable) || static::hasMacro($callable); | ||
} | ||
|
||
/** | ||
* Split provided string into callable and arguments. | ||
* | ||
* @param string $callable | ||
* @return array | ||
*/ | ||
protected function parseArgs($callable) | ||
{ | ||
$args = []; | ||
|
||
if (strpos($callable, ':') !== false) { | ||
list($callable, $argsString) = explode(':', $callable); | ||
|
||
$args = explode(',', $argsString); | ||
} | ||
|
||
return [$callable, $args]; | ||
} | ||
|
||
/** | ||
* Extract and validate class method. | ||
* | ||
* @param string $userCallable | ||
* @return callable | ||
* | ||
* @throws \Sofa\Eloquence\Mutator\InvalidCallableException | ||
*/ | ||
protected function parseClassMethod($userCallable) | ||
{ | ||
$callable = str_replace('@', '::', $userCallable); | ||
|
||
try { | ||
$method = new ReflectionMethod($callable); | ||
} catch (ReflectionException $e) { | ||
throw new InvalidCallableException($e->getMessage()); | ||
} | ||
|
||
return ($method->isStatic()) ? $callable : $this->getInstanceMethod($method, $userCallable); | ||
} | ||
|
||
/** | ||
* Get instance callable. | ||
* | ||
* @param \ReflectionMethod $method | ||
* @param string $userCallable | ||
* @return callable | ||
* | ||
* @throws \Sofa\Eloquence\Mutator\InvalidCallableException | ||
*/ | ||
protected function getInstanceMethod(ReflectionMethod $method, $userCallable) | ||
{ | ||
$class = $method->getDeclaringClass(); | ||
|
||
if (!$method->isPublic()) { | ||
throw new InvalidCallableException("Instance method [{$userCallable}] is not public."); | ||
} | ||
|
||
if (!$this->canInstantiate($class)) { | ||
throw new InvalidCallableException("Can't instantiate class [{$userCallable}]."); | ||
} | ||
|
||
return [$class->newInstance(), $method->getName()]; | ||
} | ||
|
||
/** | ||
* Determine whether instance can be instantiated. | ||
* | ||
* @param \ReflectionClass $class | ||
* @return boolean | ||
*/ | ||
protected function canInstantiate(ReflectionClass $class) | ||
{ | ||
if (!$class->isInstantiable()) { | ||
return false; | ||
} | ||
|
||
$constructor = $class->getConstructor(); | ||
|
||
return is_null($constructor) || 0 === $constructor->getNumberOfRequiredParameters(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.