/record

Immutable Validatable Records for PHP

Primary LanguagePHP

Immutable Validatable Record Build Status Coverage Status

Validatable records with an API inspired by Immutable Record (but without the memory efficiency..)

Installation

composer require prewk/record

Simple usage

  1. Extend \Prewk\Record
  2. Define fields by implementing getFields()
  3. Define (optional) defaults by implementing getDefaults()
  4. Construct a base record
  5. Create new records from that base record
<?php
class FooRecord extends \Prewk\Record
{
    /**
     * Get record fields
     * @return string[]
     */
    protected function getFields(): array
    {
        return ["foo", "bar", "baz"];
    }

    /**
     * Get defaults
     * @return array
     */
    protected function getDefaults(): array
    {
        return ["foo" => 123, "bar" => null, "baz" => 456];
    }
}

$fooRecord = new FooRecord;

// Create a FooRecord
$record1 = $fooRecord->make(["foo" => 777, "bar" => 888]);
print_r($record1->asArray());
// -> ["foo" => 777, "bar" => 888, "baz" => 456]

// Immutibility
$record1->set("foo", "This value will disappear into the void");
print_r($record1->asArray());
// -> ["foo" => 777, "bar" => 888, "baz" => 456]

$record2 = $record1->set("foo", "This value will end up in record2");
print_r($record2->asArray());
// -> ["foo" => "Yay", "bar" => 888, "baz" => 456]

Validation

  1. Implement a validator class that extends \Prewk\Record\ValidatorInterface
  2. Define rules on your record by implementing getRules()
  3. Every mutation on your record will be routed through your validator
class MyValidator implements \Prewk\Record\ValidatorInterface
{
   /**
     * Validates a value against a rule 
     * @param mixed $value
     * @param mixed $rule
     * @return bool
     */
    public function validate($value, $rule): bool
    {
        switch ($rule) {
            case "numeric":
                return is_numeric($value);
            default:
                throw new \Exception("Invalid rule!");
        }
    }
    
class FooRecord extends \Prewk\Record
{
    /**
     * Get record fields
     * @return string[]
     */
    protected function getFields(): array
    {
        return ["foo", "bar", "baz"];
    }

    /**
     * Get defaults
     * @return array
     */
    protected function getDefaults(): array
    {
        return ["foo" => 123, "bar" => null, "baz" => 456];
    }
    
    /**
     * Get rules
     * @return array
     */
    protected function getRules(): array
    {
        return ["foo" => "numeric"];
    }
}

$fooRecord = new FooRecord(new MyValidator);

$record1 = $fooRecord->make(["foo" => 100]);
print_r($record1->asArray());
// -> ["foo" => 777, "bar" => 888, "baz" => 456]

$record2 = $fooRecord->make(["foo" => "Will throw exception"]);
// -> throws exception "Field name foo didn't validate according to its rules"

Injectable Laravel validated record

<?php
class FooRecord extends \Prewk\Record\Laravel\Record
{
    protected function getFields(): array
    {
        return ["foo", "bar"];
    }
    
    protected function getRules(): array
    {
        return ["foo" => "in:1,2,3", "bar" => "numeric"];
    }
}

class FooController extends BaseController
{
    private $fooRecord;
    
    public function __construct(FooRecord $fooRecord)
    {
        $this->fooRecord = $fooRecord;
    }
    
    public function create(FooRequest $request)
    {
        $record = $this->fooRecord->make($request->all());
    }
}

API

// Make a new record from an existing record
$record->make(["foo" => "bar"]);

// Make a new record from setting
$newRecord = $record->set("foo", "bar");

// Check if a field has a value (if field has a default value this returns true)
$fooIsSet = $record->has("foo");

// Merge with an array
$newRecord = $record->merge(["baz" => "qux"]);
// ..or with an existing record
$newRecord = $record->merge($record2);

License

MIT

PHP 5

Use 1.1 for PHP versions < 7.0.