PHPackages                             railken/lem - 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. railken/lem

ActiveLibrary[API Development](/categories/api)

railken/lem
===========

v4.0.5(2y ago)034.7k7MITPHPPHP &gt;=8.2

Since Sep 18Pushed 2y ago1 watchersCompare

[ Source](https://github.com/railken/lem)[ Packagist](https://packagist.org/packages/railken/lem)[ RSS](/packages/railken-lem/feed)WikiDiscussions master Synced 2w ago

READMEChangelogDependencies (8)Versions (141)Used By (7)

Lem
===

[](#lem)

[![Actions Status](https://github.com/railken/lem/workflows/Test/badge.svg)](https://github.com/railken/lem/actions)

A precise way to structure your logic to improve readability and maintainability of your code when building API.

Requirements
============

[](#requirements)

PHP 8.1 and later.

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

[](#installation)

You can install it via [Composer](https://getcomposer.org/) by typing the following command:

```
composer require railken/lem
```

The package will automatically register itself.

Usage
-----

[](#usage)

First you need to generate a new structure folder, use:

`php artisan railken:make:manager app App\Foo`.

Now you can use it.

```
use App\Foo\FooManager;

$manager = new FooManager();
$result = $manager->create(['name' => 'foo']);

if ($result->ok()) {
    $foo = $result->getResource();
} else {
    $result->getErrors(); // All errors go here.
}
```

How can you get an Error during an operation? An error occurs when a validation or authorization fails. The cool thing about it is that you have the total control during each process: using [Validator](#modelvalidator) and [Authorizer](#modelauthorizer). When you're retrieving errors you're receiving a Collection, it goes pretty well when you're developing an api. Here's an example

```
$manager = new FooManager();
$result = $manager->create(['name' => 'f'));

print_r($result->getErrors()->toArray());
/*
Array
    (
        [0] => Array
            (
                [code] => FOO_TITLE_NOT_DEFINED
                [attribute] => title
                [message] => The title is required
                [value] =>
            )

        [1] => Array
            (
                [code] => FOO_NAME_NOT_DEFINED
                [attribute] => name
                [message] => The name isn't valid
                [value] => f
            )
    )
*/
```

So, what about the authorization part? First we have to edit the class User.

```
use Railken\Lem\Contracts\AgentContract;

class User implements AgentContract
{
    public function can($permission, $arguments = [])
    {
        return true;
    }
}
```

You can set the method can as you wish, it's better if a permission library is used such as  or .

If no system permission is needed simply leave return true.

```
use Railken\Lem\Agents\SystemAgent;

$manager = new FooManager(Auth::user());
$result = $manager->create(['title' => 'f']);

print_r($result->getErrors()->toArray());
/*
Array
    (
        [0] => Array
            (
                [code] => FOO_TITLE_NOT AUTHORIZED
                [attribute] => title
                [message] => You're not authorized to interact with title, missing foo.attributes.title.fill permission
                [value] =>
            )
    )
*
```

"foo.attributes.title.fill" is passed to User::can() and if the return is false the result will contains errors.

Note: if you don't set any agent, the SystemAgent will be used (all granted).

See [Authorizer](#modelauthorizer) for more explanations.

### Commands

[](#commands)

- Generate a new set of files `php artisan railken:make:manager [path] [namespace]`. E.g. php artisan railken:make:manager App "App\\Foo"

### Manager

[](#manager)

This is the main class, all the operations are performed using this: creating, updating, deleting, retrieving. This class is composed of components which are: validator, repository, authorizer, parameters, serializer

See [Manager](https://github.com/railken/lem/blob/master/src/Manager.php).

```
namespace App\Foo;

use Railken\Lem\Manager;
use Railken\Lem\Contracts\AgentContract;

class FooManager extends Manager
{
    /**
     * Class name entity
     *
     * @var string
     */
    public $entity = Foo::class;

    /**
     * Construct
     *
     * @param AgentContract|null $agent
     */
    public function __construct(AgentContract $agent = null)
    {
        parent::__construct($agent);
    }
}
```

### Model

[](#model)

This is the Eloquent Model, nothing changes, excepts for an interface

```
namespace App\Foo;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Railken\Lem\Contracts\EntityContract;

class Foo extends Model implements EntityContract
{

    use SoftDeletes;

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'foo';

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];

    /**
     * The attributes that should be mutated to dates.
     *
     * @var array
     */
    protected $dates = ['deleted_at'];
}
```

### Repository

[](#repository)

This is a Repository, the concept is very similar to the Repository of Symfony, code all your queries here.

See [Repository](https://github.com/railken/lem/blob/master/src/Repository.php) for more information.

```
namespace App\Foo;

use Railken\Lem\Repository;

class FooRepository extends Repository
{

    /**
     * Custom method
     *
     * @param string $name
     *
     * @return Foo
     */
    public function findOneByName($name)
    {
        return $this->findOneBy(['name' => $name]);
    }

}
```

### Validator

[](#validator)

Here comes the validator, and again it's very simple. validate() is called whenever a create/update operation is called. Remember: always return the collection of errors. You can of course add a specific library for validation and use it here.

```
namespace App\Foo;

use Railken\Lem\Contracts\EntityContract;
use Railken\Lem\Contracts\ValidatorContract;
use Railken\Lem\ParameterBag;
use Illuminate\Support\Collection;
use App\Foo\Exceptions as Exceptions;

class FooValidator implements ValidatorContract
{

    /**
     * Validate
     *
     * @param EntityContract $entity
     * @param ParameterBag $parameters
     *
     * @return Collection
     */
    public function validate(EntityContract $entity, ParameterBag $parameters)
    {

        $errors = new Collection();

        if (!$entity->exists)
            $errors = $errors->merge($this->validateRequired($parameters));

        $errors = $errors->merge($this->validateValue($entity, $parameters));

        return $errors;
    }

}
```

### Serializer

[](#serializer)

This class will serialize your model

```
namespace App\Foo;

use Railken\Lem\Contracts\SerializerContract;
use Railken\Lem\Contracts\EntityContract;
use Illuminate\Support\Collection;
use Railken\Bag;

class FooSerializer implements SerializerContract
{

	/**
	 * Serialize entity
	 *
	 * @param EntityContract $entity
	 *
	 * @return Bag
	 */
    public function serialize(EntityContract $entity, Collection $select)
    {
        $bag = (new Bag($entity->toArray()))->only($select->toArray());

		return $bag;
	}

}
```

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity21

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity93

Battle-tested with a long release history

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

Recently: every ~3 days

Total

140

Last Release

805d ago

Major Versions

v1.0.1 → v2.0.02017-09-19

v2.8.0 → v3.0.02018-03-18

v3.3.7 → v4.0.02024-03-27

PHP version history (4 changes)v1.0.0PHP &gt;=5.6.4

v2.1.0PHP &gt;=7.0.0

v3.1.11PHP &gt;=7.1

v4.0.0PHP &gt;=8.2

### Community

Maintainers

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

---

Top Contributors

[![railken](https://avatars.githubusercontent.com/u/26530231?v=4)](https://github.com/railken "railken (511 commits)")

---

Tags

apientityentity-managerlaravellibrarymanagerphpvalidationlaravel

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/railken-lem/health.svg)

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

###  Alternatives

[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1155.2k](/packages/rcsofttech-audit-trail-bundle)[knuckleswtf/scribe

Generate API documentation for humans from your Laravel codebase.✍

2.3k13.5M59](/packages/knuckleswtf-scribe)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.8M712](/packages/sylius-sylius)[statamic/cms

The Statamic CMS Core Package

4.8k3.5M916](/packages/statamic-cms)[tempest/framework

The PHP framework that gets out of your way.

2.2k31.1k12](/packages/tempest-framework)[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k9.9M89](/packages/dedoc-scramble)

PHPackages © 2026

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