Git Product home page Git Product logo

lean's Introduction

Lean

Latest Stable Version Build Status Coverage Status

Lean allows you to use the PHP League's Container package with auto-wiring support as the core container in Slim 3.

Install

Via Composer

$ composer require jenssegers/lean

Usage

The easiest way to start using Lean is simply creating a Jenssegers\Lean\App instance:

require 'vendor/autoload.php';

$app = new \Jenssegers\Lean\App();

$app->get('/hello/{name}', function (Request $request, Response $response, string $name) {
    return $response->write('Hello, ' . $name);
});

$app->run();

Behind the scenes, a Slim application is bootstrapped by adding all of the required Slim components to League's container.

Service Providers

Service providers give the benefit of organising your container definitions along with an increase in performance for larger applications as definitions registered within a service provider are lazily registered at the point where a service is retrieved.

To build a service provider it is as simple as extending the base service provider and defining what you would like to register.

use League\Container\ServiceProvider\AbstractServiceProvider;

class SomeServiceProvider extends AbstractServiceProvider
{
    /**
     * The provided array is a way to let the container
     * know that a service is provided by this service
     * provider. Every service that is registered via
     * this service provider must have an alias added
     * to this array or it will be ignored.
     */
    protected $provides = [
        SomeInterface::class,
    ];

    /**
     * This is where the magic happens, within the method you can
     * access the container and register or retrieve anything
     * that you need to, but remember, every alias registered
     * within this method must be declared in the `$provides` array.
     */
    public function register()
    {
        $this->getContainer()
            ->add(SomeInterface::class, SomeImplementation::class);
    }
}

To register this service provider with the container simply pass an instance of your provider or a fully qualified class name to the League\Container\Container::addServiceProvider method.

$app = new \Jenssegers\Lean\App();
$app->getContainer()->addServiceProvider(\Acme\ServiceProvider\SomeServiceProvider::class);

Read more about service providers here.

Settings

You can access Slim's internal configuration through the settings key on the container:

$app = new \Jenssegers\Lean\App();

$app->getContainer()->get('settings')['displayErrorDetails'] = true;

Alternatively, an alias is registered that allows a bit more fluent way of working with settings:

$app = new \Jenssegers\Lean\App();

$app->getContainer()->get(\Slim\Settings::class)->set('displayErrorDetails', true);

Read more about the available configuration options here.

Route arguments

By default, Lean will use method injection to pass arguments to your routes. This allows you to type-hint dependencies on method level (similar to the Laravel framework).

Route arguments will be passed as individual arguments to your method:

$app->get('/books/{id}', function (Request $request, Response $response, string $id) {
    ...
});

They are also accessible through the getAttribute method.

$app->get('/books/{id}', function (Request $request, Response $response) {
    $id = $request->getAttribute('id');
    ....
});

If you want to disable this behaviour and use the default Slim way of route arguments, you can disable this feature be setting methodInjection to false:

$app->getContainer()->get(\Slim\Settings::class)->set('methodInjection', false);

Read more about routes here.

Error Handlers

By default, Lean uses Slim's error handlers. There are different ways to implement an error handler for Slim, read more about them here.

Typically you would create a custom error handler class that looks like this:

class CustomErrorHandler
{
    public function __invoke(ServerRequestInterface $request, Response $response, Throwable $exception)
    {
        return $response->withJson([
            'error' => 'Something went wrong',
        ], 500);
    }
}

Then you overwrite the default handler by adding it to the container:

$app = new Jenssegers\Lean\App();

$app->getContainer()->share('errorHandler', function () {
    return new CustomErrorHandler();
});

Ideally, you would put this code inside a service provider. Read more about service providers above.

Testing

$ php ./vendor/bin/phpunit

License

The MIT License (MIT).

lean's People

Contributors

jenssegers avatar wouterds avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

lean's Issues

Possible to set errorHandler, etc?

I admit I’m new to OOP, but I’ve setup Slim to override its internal errorHandler to use Monolog using Pimple before. I cannot for the life of me figure out how to do it using this package though?

errorHandler not being handled

I have a slim project that has a custom errorHandler setup. It was working great before switching over to the league container. I have made a service provider for the errorHandler after trying the basic way of $container->share('errorHandler' function{}); and returning the custom handler.

This is the customer handler:

use \Exception;
use \ReflectionClass;

class Handler
{
	public function __invoke($request, $response, $exception)
	{
		die('HERE');
		$shortName = $this->getExceptionShortName($exception);

		if(method_exists($this, $handler = "handle{$shortName}")){
			return $this->{$handler}($request, $response, $exception);
		}

		return $this->rethrowException($exception);
	}

	protected function getExceptionShortName(Exception $e)
	{
		return (new ReflectionClass($e))->getShortName();
	}

	protected function handleValidationFailedException($request, $response, $exception)
	{
		return $exception->getReturn();
	}

	protected function handleFileNotFoundException($request, $response, $exception)
	{
		return $response->withStatus(404)->write('Not Found');
	}

	protected function rethrowException(Exception $e)
	{
		throw $e;
	}
}

Then I try to throw this exception in the controller:

namespace App\Exceptions;

class ValidationFailedException extends \Exception
{
	protected $request;
	protected $response;
	protected $container;
	protected $errors;

	public function __construct($request, $response, $container, string $errors)
	{
		$this->request = $request;
		$this->response = $response;
		$this->container = $container;
		$this->errors = $errors;
	}

	protected function getPath()
	{
		return $this->request->getUri()->getPath();
	}

	public function getReturn()
	{
		if($this->request->getParam('ajax')){
			return $this->container->get('ajaxJson')->message($this->errors)->sendResponse($this->response);
		}

		return $this->response->withRedirect($this->getPath());
	}
}

This is the code that throws the exception:

if($check->failed()){
			throw new ValidationFailedException($request, $response, $this->container, $this->errorMessageBox($check->errors()));
		}

The furthest that the exception gets is the __construct and then the browser just returns the exception rather than calling the getReturn() like it should. I'm stuck on this.

Dependency Injection for Controller

Does this package allow for DI in the controller? I'm trying to integrate it into an already existing slim project but when I try to type-hint a class in the controller method being called, it's not allowing it to be autowired in.

Am I doing something wrong or does this package not work for that aspect of Slim3

Unable to resolve a value for parameter (path) in the function/method (__construct)

I have a similar issue to #11

use Jenssegers\Lean\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Settings;

require __DIR__ . '/../vendor/autoload.php';

$app = new App();

$container = $app->getContainer();
$container->get('settings')->set('displayErrorDetails', true);

$app->get('/hello/{name}', function (Request $request, Response $response, string $name) {
    return $response->write('Hello, ' . $name);
});

$app->run();

Error:

Slim Application Error
The application could not run because of the following error:

Details

Type: League\Container\Exception\NotFoundException
Message: Unable to resolve a value for parameter (path) in the function/method (__construct)
File: /Users/andrew/apis/lean/vendor/league/container/src/Argument/ArgumentResolverTrait.php
Line: 78

method injection throws League\Container\Exception\NotFoundException

Am having an issue with making the App run with method Injection 💉 enabled.

This is the only code I have on index.php file

use Jenssegers\Lean\App;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Settings;

require __DIR__ . '/../vendor/autoload.php';

$app = new App();

$container = $app->getContainer();

$container->get(Settings::class)->replace([
    'displayErrorDetails' => true,
]);

// when this is commented, It doesn't work, at all
$app->getContainer()->get(Settings::class)->set('methodInjection', false);

$app->get('/hello/{name}', function (Request $request, Response $response) {
    $name = $request->getAttribute('name');
    return $response->write('Hello, ' . $name);
});

$app->run();

Here is the Error

Slim Application Error
The application could not run because of the following error:

Details
Type: League\Container\Exception\NotFoundException
Message: Unable to resolve a value for parameter (method) in the function/method (__construct)
File: C:\Users\nkosg\PhpstormProjects\mychama\vendor\league\container\src\Argument\ArgumentResolverTrait.php
Line: 78
Trace
#0 [internal function]: League\Container\ReflectionContainer->League\Container\Argument\{closure}(Object(ReflectionParameter))
#1 C:\Users\nkosg\PhpstormProjects\mychama\vendor\league\container\src\Argument\ArgumentResolverTrait.php(83): array_map(Object(Closure), Array)
#2 C:\Users\nkosg\PhpstormProjects\mychama\vendor\league\container\src\ReflectionContainer.php(52): League\Container\ReflectionContainer->reflectArguments(Object(ReflectionMethod), Array)
#3 C:\Users\nkosg\PhpstormProjects\mychama\vendor\league\container\src\Argument\ArgumentResolverTrait.php(44): League\Container\ReflectionContainer->get('Slim\\Http\\Reque...')
#4 C:\Users\nkosg\PhpstormProjects\mychama\vendor\league\container\src\Argument\ArgumentResolverTrait.php(85): League\Container\ReflectionContainer->resolveArguments(Array)
#5 C:\Users\nkosg\PhpstormProjects\mychama\vendor\league\container\src\ReflectionContainer.php(103): League\Container\ReflectionContainer->reflectArguments(Object(ReflectionMethod), Array)
#6 C:\Users\nkosg\PhpstormProjects\mychama\vendor\jenssegers\lean\src\Lean\MethodInjection.php(37): League\Container\ReflectionContainer->call(Object(Closure), Array)
#7 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\Route.php(356): Jenssegers\Lean\MethodInjection->__invoke(Object(Closure), Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#8 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\MiddlewareAwareTrait.php(117): Slim\Route->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#9 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\Route.php(334): Slim\Route->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#10 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\App.php(515): Slim\Route->run(Object(Slim\Http\Request), Object(Slim\Http\Response))
#11 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\MiddlewareAwareTrait.php(117): Slim\App->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#12 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\App.php(405): Slim\App->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#13 C:\Users\nkosg\PhpstormProjects\mychama\vendor\slim\slim\Slim\App.php(313): Slim\App->process(Object(Slim\Http\Request), Object(Slim\Http\Response))
#14 C:\Users\nkosg\PhpstormProjects\mychama\public\index.php(29): Slim\App->run()
#15 {main}

Package versions

"php": ">=7.3",
"jenssegers/lean": "^1.0",
 "slim/slim": "^3.1",

Any Ideas on what I might be doing wrong?

Example not working

I'm try use this project but I got exception in example.

In empty folder I install slim & lean:

composer require slim/slim "^3.0"
composer require jenssegers/lean

next I make index.php:

<?php
require 'vendor/autoload.php';

$app = new Jenssegers\Lean\App();
$app->get('/hello/{name}', function ($request, $response, $args) {
    return $response->getBody()->write("Hello, " . $args['name']);
});

$app->run();

start build-in web-server:

php -S localhost:8000

and go to http://localhost:8000/hello/world
in console I got stack trace:

[Sun Feb  4 13:00:05 2018] Slim Application Error:
Type: League\Container\Exception\NotFoundException
Message: Unable to resolve a value for parameter (request) in the function/method (__invoke)
File: /Users/oleg/projects/self/slim/vendor/league/container/src/Argument/ArgumentResolverTrait.php
Line: 68
Trace: #0 [internal function]: League\Container\ReflectionContainer->League\Container\Argument\{closure}(Object(ReflectionParameter))
#1 /Users/oleg/projects/self/slim/vendor/league/container/src/Argument/ArgumentResolverTrait.php(73): array_map(Object(Closure), Array)
#2 /Users/oleg/projects/self/slim/vendor/league/container/src/ReflectionContainer.php(80): League\Container\ReflectionContainer->reflectArguments(Object(ReflectionMethod), Array)
#3 /Users/oleg/projects/self/slim/vendor/league/container/src/Container.php(211): League\Container\ReflectionContainer->call(Object(Closure), Array)
#4 /Users/oleg/projects/self/slim/vendor/jenssegers/lean/src/Lean/Strategies/AutoWiringStrategy.php(42): League\Container\Container->call(Object(Closure), Array)
#5 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/Route.php(335): Jenssegers\Lean\Strategies\AutoWiringStrategy->__invoke(Object(Closure), Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#6 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(117): Slim\Route->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#7 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/Route.php(313): Slim\Route->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#8 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/App.php(495): Slim\Route->run(Object(Slim\Http\Request), Object(Slim\Http\Response))
#9 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(117): Slim\App->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#10 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/App.php(388): Slim\App->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#11 /Users/oleg/projects/self/slim/vendor/slim/slim/Slim/App.php(296): Slim\App->process(Object(Slim\Http\Request), Object(Slim\Http\Response))
#12 /Users/oleg/projects/self/slim/index.php(16): Slim\App->run()
#13 {main}

If I replace LeanApp by SlimApp application work well

Middleware not working properly, autowiring issue?

I seen one of the latest tickets is related to the getAttributes() request method however my issue is related to using the ip-addr-middleware package to grab the client ip from the request and since it uses ->getAttributes, perhaps my problem is semi-related.

So I added the ip-addr-middleware package exactly as described in the docs (https://github.com/akrabat/ip-address-middleware) and while I can retrieve the ip address using the example route shown in that doc, getAttributes() is empty on my auto-wired controllers. Im curious if this is because when the route is __invoke’d it is instantiating a new request object or if theres some other configuration issue that I completely screwed up, any ideas what could cause this?

Url attributes not coming through

I can't seem to get any of the url parameters to come through in a controller or route. I have switched everything over from a base Slim project that was previously working. I have not changed the routes or controllers other than adding the Request and Response type to the method signatures.

It appears that the traditional way of using $args is not working as it gives this error:
Fatal error: Uncaught League\Container\Exception\NotFoundException: Unable to resolve a value for parameter (args) in the function/method (__invoke) in D:\rsleagueslim\vendor\league\container\src\Argument\ArgumentResolverTrait.php on line 78

This error happens even using your basic example in your Docs. I have tried using the other Slim ways to get the attributes by using $request->getAttribute('xyz'); and $request->getAttributes(); Both those methods return empty. Here is another example route and controller I had previously that no longer sees the attribute in the url.

class CheckOutController extends BaseController
{
	public function index(Request $request, Response $response)
	{
		$customer = $this->Customer->with(['jobs', 'sheets'])->find($request->getAttribute('customer'));
		
		if(!$customer || !$customer->sheets->get(0) || count($customer->sheets) > 1)
		{
			return redirect('home');
		}

		$employees = auth()->employees()->get();
		$radios = $customer->sheets->get(0)->subscribed_fields;

		return $this->twig->render($response, 'services/checkout.twig', $this->sendToView(['customer' => $customer, 'employees' => $employees, 'radios' => $radios]));
	}
}

And route which is inside a route group.
$this->get('/checkout/customer/{customer: [0-9]+}', CheckOutController::class.':index')->setName('checkout.index');

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.