PHPackages                             michaeljennings/refinery - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. michaeljennings/refinery

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

michaeljennings/refinery
========================

A php class to refine data into a set format.

v1.2.2(8y ago)129.5k↓33.3%3[1 PRs](https://github.com/michaeljennings/refinery/pulls)2MITPHPPHP &gt;=5.4.0

Since Apr 19Pushed 6y ago1 watchersCompare

[ Source](https://github.com/michaeljennings/refinery)[ Packagist](https://packagist.org/packages/michaeljennings/refinery)[ RSS](/packages/michaeljennings-refinery/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (8)Dependencies (2)Versions (9)Used By (2)

Refinery [![Latest Stable Version](https://camo.githubusercontent.com/fb72de52da5814d45b6a6088073a7e697a336a7ad0468ee4fa72c27bc536e8d1/68747470733a2f2f706f7365722e707567782e6f72672f6d69636861656c6a656e6e696e67732f726566696e6572792f762f737461626c65)](https://packagist.org/packages/michaeljennings/refinery) [![Build Status](https://camo.githubusercontent.com/c7ee8b04e272f442820067ae25eb1a1227c5c809c7be898c6ffba6a3adfe6ee5/68747470733a2f2f7472617669732d63692e6f72672f6d69636861656c6a656e6e696e67732f726566696e6572792e7376673f6272616e63683d76302e312e31)](https://travis-ci.org/michaeljennings/refinery)
==========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================

[](#refinery--)

This project aims to add a layer of abstraction between your backend data store and the front end code. If you make an edit to the way your data is stored this can often end up in you needing to make a lot of front end changes. This project helps by formatting your data in one place so that if your back end changes, it won't effect the rest of your website.

Example
-------

[](#example)

Below is a basic example of how to use refinery.

```
// Here we have a product we want to refine
class Product
{
    public $price = 10
    public $description = 'Something really cool!'
}

// So we create a product refinery where we set the product template
class ProductRefinery extends Refinery
{
    public function setTemplate($product)
    {
        return [
            'price' => number_format($product->price, 2),
            'description' => $product->description,
            'full_description' => $product->description . ' For only £' . number_format($product->price, 2),
        ];
    }
}

// Then we create the instances and refine the product
$product = new Product();
$refinery = new ProductRefinery();

var_dump($refinery->refine($product));

// The above will output:
// ['price' => '10.00', 'description' => 'Something really cool!', 'full_description' => 'Something really cool! For only £10.00']
```

Navigation
----------

[](#navigation)

- [Installation](#installation)
- [Usage](#usage)
    - [Example Usage](#example-usage)
- [Multidimensional Refining](#multidimensional-refining)
- [Advanced Refining](#advanced-refining)
    - [Using External Data](#using-external-data)
    - [Custom Attachments](#custom-attachments)
    - [Raw Attachments](#raw-attachments)

Installation
------------

[](#installation)

Run `composer require michaeljennings/refinery`.

Or add the package to your `composer.json`.

```
"michaeljennings/refinery": "~1.0";

```

Usage
-----

[](#usage)

To create a new refinery simply extend the `Michaeljennings\Refinery\Refinery`.

```
use Michaeljennings\Refinery\Refinery;

class Foo extends Refinery
{

}
```

The refinery has one abstract method which is `setTemplate`. The setTemplate method is passed the item being refined and then you just need to return it in the format you want.

```
class Foo extends Refinery
{
  public function setTemplate($data)
  {
    // Refine data
  }
}
```

To pass data to the refinery, create a new instance of the class and then use the `refine` method.

```
$foo = new Foo;

$foo->refine($data);
```

You can pass the refinery either a single item or a multidimensional item.

```
$foo = new Foo;

$data = $foo->refine(['foo', 'bar']);
$multiDimensionalData = $foo->refine([['foo'], ['bar']]);
```

### Example Usage

[](#example-usage)

As an example if I had a product and I wanted to make sure that its price always had two decimal figures I could do the following.

```
class Product {
  public price = '10';
}

class ProductRefinery extends Refinery {
  public function setTemplate($product)
  {
    return [
      'price' => number_format($product->price, 2),
    ];
  }
}

$product = new Product();
$refinery = new ProductRefinery();

$refinedProduct = $refinery->refine($product); // ['price' => 10.00]
```

Multidimensional Refining
-------------------------

[](#multidimensional-refining)

When you are working with database data, particularly relational data, it's common that you won't just be refining the main entity, you may have parent and child data that also needs to be refined.

This is best displayed with an example. Below we have a product that has many variants, and belongs to a category.

```
$product = [
    'name' => 'Awesome Product',
    'description' => 'This is an awesome product',
    'price' => 10.00,
    'category' => [
        'name' => 'Awesome Products',
    ],
    'variants' => [
        [
            'size' => 'Medium',
        ],
        [
            'size' => 'Large',
        ]
    ]
]
```

This parent and child data will usually be refined in the same way in every area it is used within your application, therefore it makes sense to move it into it's own class so that it can be reused.

To do that we use attachments.

Below we have a product refinery, that has category and variant attachments.

```
class ProductRefinery extends Refinery
{
    public function setTemplate($product)
    {
        return [
            'name' => $product['name'],
            'description' => $product['description'],
            'price' => '£' . number_format($product['price'], 2),
        ];
    }

    public function category()
    {
        return $this->attach(CategoryRefinery::class);
    }

    public function variants()
    {
        return $this->attach(CategoryRefinery::class);
    }
}
```

These attachments will only be brought with the item when the `bring` method is called when refining.

```
// Will just refine the product data.
$refinedProduct = $productRefinery->refine($product);

// Will refine the product, category, and the variants.
$refinedProductWithAttachments $productRefinery->bring('category', 'variants')->refine($product);
```

When you attempt to bring attachments it will look for methods on the refinery class with the specified attachment name.

For example if we were to do the following:

```
$refinedProductWithAttachments $productRefinery->bring('category')->refine($product);
```

There would need to be a method called `category` on our product refinery.

The refinery will then attempt to pass the category property from the product to the category refinery.

Attachments can also be multidimensional. For example below we are bringing a product with it's category, and then we are bringing the category's meta data.

```
$refined = $productRefinery->bring(['category' => ['meta']])->refine($product);
```

This will look for the category attachment on the product refinery, and then a meta attachment on the category refinery.

Advanced Refining
-----------------

[](#advanced-refining)

### Using External Data

[](#using-external-data)

When refining you may need to access data that is not part of the main object.

For example, below we want to get the correct currency symbol for the country the user is in, however the country cannot be accessed from the product.

To get around this we use the `with` method to pass through the current country to the product refinery.

```
$country = [
    'name' => 'United Kingdom',
    'symbol' => '£',
];

$refined = $productRefinery->with(['country' => $country])->refine($product);
```

Then in the `setTemplate` method in the refinery we can access the country as shown below.

```
class ProductRefinery extends Refinery
{
    public function setTemplate($product)
    {
        $symbol = $this->country['symbol'];
        // OR
        $symbol = $this->attributes['country']['symbol'];

        return [
            'name' => $product['name'],
            'description' => $product['description'],
            'price' => $symbol . number_format($product['price'], 2),
        ];
    }
}
```

### Custom Attachments

[](#custom-attachments)

Occasionally you may want to set attachments that don't actually exist in the original data.

For example below we have added a `largeVariant` attachment to our product refinery.

By passing a closure to the second argument of the `attach` method we can choose what data we want to send to the refinery. The closure will be passed the current item being refined, which in this case is the product.

```
class ProductRefinery extends Refinery
{
    public function largeVariant()
    {
        return $this->attach(VariantRefinery::class, function($product) {
            return array_filter($product['variants'], function($variant) {
                return $variant['size'] == 'Large';
            });
        });
    }
}
```

### Raw Attachments

[](#raw-attachments)

Refining can also be performed without a preset class, for instance if you want to refine a multidimensional array to a single array.

Below we have added an attachment which gets all of the sizes for a product and returns it as an array.

```
class ProductRefinery extends Refinery
{
    public function sizes()
    {
        return $this->attach(function($product) {
            $sizes = [];

            foreach ($product['variants'] as $variant) {
                $sizes[] = $variant['size'];
            }

            return $sizes;
        });
    }
}
```

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity33

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~143 days

Recently: every ~137 days

Total

8

Last Release

3044d ago

Major Versions

v0.1.2 → v1.02016-07-17

### Community

Maintainers

![](https://www.gravatar.com/avatar/df807d0371b1b265ea1becedfa4001428f278e7632c6d175e2afb2921f5788a3?d=identicon)[michaeljennings](/maintainers/michaeljennings)

---

Top Contributors

[![michaeljennings](https://avatars.githubusercontent.com/u/5189701?v=4)](https://github.com/michaeljennings "michaeljennings (52 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/michaeljennings-refinery/health.svg)

```
[![Health](https://phpackages.com/badges/michaeljennings-refinery/health.svg)](https://phpackages.com/packages/michaeljennings-refinery)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
