PHPackages                             label305/dug - 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. [API Development](/categories/api)
4. /
5. label305/dug

AbandonedArchivedLibrary[API Development](/categories/api)

label305/dug
============

Adding elegance to defining your webservices

0.0.2(9y ago)2221[1 issues](https://github.com/Label305/Dug/issues)Apache-2.0PHP

Since Aug 2Pushed 9y ago1 watchersCompare

[ Source](https://github.com/Label305/Dug)[ Packagist](https://packagist.org/packages/label305/dug)[ RSS](/packages/label305-dug/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependencies (3)Versions (4)Used By (0)

Dug
===

[](#dug)

[![Build Status](https://camo.githubusercontent.com/f17ffb6d0ef3bdfba764c63b0aa3d74e14f5ee750f901783e76897ae08a82667/68747470733a2f2f7472617669732d63692e6f72672f4c6162656c3330352f4475672e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/Label305/Dug)

For combining different data sources to create webservice responses efficiently and manageable.

**Experimental**

This library is highly experimental, use at your own risk!

The problem
-----------

[](#the-problem)

When managing a RESTful api you want responses to be consistent and composable, for example fetching a user:

```
{
    "id": 1,
    "name": "John",
    "friend_count": 30
}

```

This often requires the combination of fetching a user and adding an `friend_count`. While this is manageable for a single user, when you want to include a `user` object inside of another object, you have to make sure these fields are included to be consistent.

While your api grows it is harder to see how every object is composed, this is where Dug comes into play.

Dug allows you to point to sources providing certain data, each of these sources can refer to one another and compose their data.

Basic usage
-----------

[](#basic-usage)

First of all we setup a dug

```
$dug = new Dug();

```

Then register your first data fetching source, which will fetch a bunch of users from the database. Note that `$path[1]` contains an array with results that matched `/[0-9]+/` so you can combine the query.

```
$source = Source::build(['users', '/[0-9]+/'], function($path) {
    $users = User::whereIn('id', $path[1])->get();

    $result = [];
    foreach($users as $user) {
        $result[] = Data::build(
            ['users', $user->getId()],
            [
               'id' => $user->getId(),
               'name' => $user->getName()
            ]
        );
    }

    return $result;
});

```

To fetch data you can request data from a source:

```
$dug->fetch(['users', [1,2]]);

```

Which will result in the array:

```
[
    [
        "id' => 1,
        "name' => "Name of user 1",
    ],
    [
        "id' => 2,
        "name' => "Name of user 2",
    ]
]

```

Composing
---------

[](#composing)

Let's take the example from Basic usage but in this case we add the unread count

```
$source = Source::build(['users', '/[0-9]+/'], function($path) {
    $users = User::whereIn('id', $path[1])->get();

    $result = [];
    foreach($users as $user) {
        $result[] = Data::build(
            ['users', $user->getId()],
            [
               'id' => $user->getId(),
               'name' => $user->getName()
           ]
       );
    }

    $unreadCounts = Counters::whereIn('user_id', $path[1])->get();
    foreach($unreadCounts as $unreadCount) {
        $result[] = Data::build(
            ['users', $unreadCount->getUserId()],
            [
               'unread_count' => $unreadCount->getValue()
            ]
        );
    }

    return $result;
});

```

Since the first argument of `Data::build` (the source) will be the same for fetching user data, as well as for fetching the unread counts; e.g. `['users', 1]`. Dug knows it can combine the results of those two.

```
[
    [
        "id' => 1,
        "name" => "Name of user 1",
        "unread_count" => 123
    ],
    [
        "id' => 2,
        "name" => "Name of user 2",
        "unread_count" => 0
    ]
]

```

References
----------

[](#references)

Now imagine we have users who belong to a company, so you'll have an endpoint called `companies/1` to fetch a single company, but you'll also have an endpoint `users/2` to fetch a single user. Since every user has only one company and the company specification doesn't change that much, you'll probably want to include the company directly within the user object, as so:

```
[
    "id" => 2,
    "name" => "John",
    "company" => {
        "id" => 1,
        ...
    }
]

```

Now a problem arises, you have a definition what a company looks like in your api, but you want to keep them in sync between the `companies/1`and `users/1` endpoint. This is where references come in.

```
$source = Source::build(['users', '/[0-9]+/'], function($path) {
    $users = User::whereIn('id', $path[1])->get();

    $result = [];
    foreach($users as $user) {
        $result[] = Data::build(
            ['users', $user->getId()],
            [
               'id' => $user->getId(),
               'name' => $user->getName(),
               'company' => new ReferenceToSingle(['companies', $user->getCompany()])
           ]
    }

    return $result;
});

```

This assumes you have registered another source `['companies', '/[0-9]+/']`which will return companies. Dug will resolve the reference by fetching data from this source and merge it with the user object.

Since Dug first combines al data it will also combine all references to check if it can combine calls to your `['companies', '/[0-9]+/']`source in case you fetched multiple users, and possibly multiple companies. Meaning it will make only one round trip to your `['companies', '/[0-9]+/']`source!

Dependency Injection
--------------------

[](#dependency-injection)

When your api grows you don't want everything done within closures, for this we have `DataProvider` classes. For example:

```
class UserProvider implements DataProvider {
    public function handle(array $path):array
        //Your magic
    }
}

```

Which you can register as a source by their classname:

```
Source::build(['users', '/[0-9]+/'], UserProvider::class);

```

By default Dug will simply create an instance of this class, however since you might have a dependency injection framework lying around you might want to use that to initiate classes and inject stuff into your constructor. This can be done using a `ClassInitializer`:

```
class LaravelClassInitializer implements ClassInitializer {
    public function inititialize(string $className) {
        return app($className);
    }
}

$dug = new Dug();
$dug->setClassInitializer(new LaravelClassInitializer());

```

License
-------

[](#license)

Copyright 2016 Label305 B.V.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

###  Health Score

23

—

LowBetter than 26% of packages

Maintenance10

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 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 ~0 days

Total

2

Last Release

3611d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/411527?v=4)[Label305](/maintainers/Label305)[@Label305](https://github.com/Label305)

---

Top Contributors

[![JBlaak](https://avatars.githubusercontent.com/u/410113?v=4)](https://github.com/JBlaak "JBlaak (7 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/label305-dug/health.svg)

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

###  Alternatives

[exsyst/swagger

A php library to manipulate Swagger specifications

35816.3M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24015.5M18](/packages/hubspot-api-client)[botman/driver-telegram

Telegram driver for BotMan

93452.6k6](/packages/botman-driver-telegram)

PHPackages © 2026

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