Skip to content

Instantly share code, notes, and snippets.

@jakewtaylor
Last active September 23, 2019 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakewtaylor/5eb186f7af596aa8731fe29d1ccf26d8 to your computer and use it in GitHub Desktop.
Save jakewtaylor/5eb186f7af596aa8731fe29d1ccf26d8 to your computer and use it in GitHub Desktop.
<?php
use Illuminate\Support\Str;
$method = 'whereBoardingType';
// Currently, you need to do something like this in PHP
$method = 'whereBoardingType';
$method = Str::substr($method, 5);
$method = Str::snake($method);
$method = Str::plural($method);
// but now, you can do this:
$key = take($method)
->scope(Str::class) // scopes all subsequent methods to this class
->pipe('substr', 5)
->pipe('snake')
->pipe('plural')
->complete();
// $key === 'boarding_types'
///////////////////////////////
$subdomain = take('https://www.example.com')
->pipe('parse_url', PHP_URL_HOST) // value is always passed as first parameter - parse_url($value, PHP_URL_HOST)
->pipe('explode', '.', '$$') // unless you pass a '$$' - explode('.', $value)
->pipe('reset')
->complete();
// $subdomain === 'www'
///////////////////////////////
// Thanks to __call you can just use method names if you want.
// You can also pass a scope as the 2nd parameter to take for slightly more terse code.
$key = take($method, Str::class)
->substr(5)
->snake()
->plural()
->complete();
<?php
if (!function_exists('take')) {
function take(...$args)
{
return Piper::make(...$args);
}
}
<?php
namespace App\Helpers;
use Illuminate\Support\Collection;
class Piper
{
/**
* The symbol that will be replaced with the current value.
*
* @var string
*/
const SYMBOL = '$$';
/**
* The current value.
*
* @var mixed
*/
protected $value;
/**
* Class to scope calls to.
*
* @var string
*/
protected $scope;
/**
* Constructs the piper.
*
* @param mixed $value
*/
public function __construct($value, $scope = null)
{
$this->value = $value;
$this->scope = $scope;
}
/**
* Applies a pipe to the value.
*
* @param mixed $callable
* @param mixed ...$args
* @return self
*/
public function pipe($callable, ...$args): self
{
$callable = $this->getCallable($callable);
$args = $this->getArgs($args);
return $this->applyPipe($callable, $args);
}
/**
* Returns the final value.
*
* @return mixed
*/
public function complete()
{
return $this->value;
}
/**
* Scopes the piper to the specified class.
*
* @param string $scope
* @return self
*/
public function scope(string $scope): self
{
$this->scope = $scope;
return $this;
}
/**
* Builds the args array.
*
* @param array $args
* @return array
*/
protected function getArgs(array $args): array
{
$args = Collection::wrap($args);
if ($this->hasValueSymbol($args)) {
return $this->replaceValueSymbol($args)->toArray();
}
return $args->prepend($this->value)->toArray();
}
/**
* Gets a callable value from the provided value.
*
* @param mixed $callable
* @return callable
*/
protected function getCallable($callable): callable
{
if (is_string($callable) && $this->scope) {
return [$this->scope, $callable];
}
return $callable;
}
/**
* Applies the specified pipes and updates the value.
*
* @param callable $callable
* @param array $args
* @return self
*/
protected function applyPipe(callable $callable, array $args): self
{
// We check for string global methods because
// sometimes some built in PHP methods raise
// an 'expected to be reference, value given'
// warning when used with call_user_func
if (is_string($callable)) {
$this->value = $callable(...$args);
} else {
$this->value = call_user_func($callable, ...$args);
}
return $this;
}
/**
* Determines if the value symbol is in the args collection.
*
* @param Collection $args
* @return boolean
*/
protected function hasValueSymbol(Collection $args): bool
{
return $args->contains(self::SYMBOL);
}
/**
* Replaces the value symbol in the args collection.
*
* @param Collection $args
* @return Collection
*/
protected function replaceValueSymbol(Collection $args): Collection
{
return $args->map(function ($arg) {
return $arg === self::SYMBOL
? $this->value
: $arg;
});
}
/**
* Statically creates an instance of Piper.
*
* @param mixed ...$args
* @return self
*/
public static function make(...$args): self
{
return new static(...$args);
}
/**
* Allows dynamic calls as pipes.
*
* @param string $method
* @param array $args
* @return self
*/
public function __call(string $method, array $args)
{
return $this->pipe($method, ...$args);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment