Skip to content

Releases: bearsunday/BEAR.Package

1.3.0

31 May 10:11
Compare
Choose a tag to compare
  • [ADD] PSR logger support #240
  • [UPDATE] Error handling #241
  • [ADD] Support @Curies (Compact URIs) annotation for API docs #239
  • [ADD] Support @ReturnCreatedResource annotation for 201 Created response and Location header #239

PSR Logger

Monolog logger installed in default.

binding

    protected function configure()
    {
        $this->bind(LoggerInterface::class)->toProvider(MonologProviver::class)->in(Scope::SINGLETON);
    }

You can change in logger in your ProdModule. The default logger provider is like this.

logger Provider

class ProdMonologProviver implements ProviderInterface
{
    /**
     * @var AbstractAppMeta
     */
    private $appMeta;

    /**
     * @param AbstractAppMeta $appMeta
     */
    public function __construct(AbstractAppMeta $appMeta)
    {
        $this->appMeta = $appMeta;
    }

    public function get()
    {
        return new Logger($this->appMeta->name, [new ErrorLogHandler]);
    }
}

You may change to your own logger in your prod module.

Error handler

Change binding ErrorInterface and have your own error handling.

namespace BEAR\Package\Provide\Error;

final class ErrorHandler implements ErrorInterface
{
    /**
     * @var ResourceObject
     */
    private $errorPage;

    /**
     * @var TransferInterface
     */
    private $responder;

    /**
     * @var ErrorLogger
     */
    private $logger;

    /**
     * @var ErrorPageFactoryInterface
     */
    private $factory;

    public function __construct(TransferInterface $responder, ErrorLogger $logger, ErrorPageFactoryInterface $factory)
    {
        $this->responder = $responder;
        $this->logger = $logger;
        $this->factory = $factory;
    }

    /**
     * {@inheritdoc}
     */
    public function handle(\Exception $e, Request $request)
    {
        $this->logger->__invoke($e, $request);
        $this->errorPage = $this->factory->newInstance($e, $request);

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function transfer()
    {
        $this->responder->__invoke($this->errorPage, []);
    }
}

Error Page

namespace BEAR\Package\Provide\Error;

use BEAR\Resource\ResourceObject;
use BEAR\Sunday\Extension\Router\RouterMatch;

final class ProdVndErrorPage extends ResourceObject
{
    public function __construct(\Exception $e, RouterMatch $request)
    {
        $status = new Status($e);
        $this->code = $status->code;
        $this->headers = $this->getHeader($status->code);
        $this->body = $this->getResponseBody($e, $request, $status);
    }

    public function toString()
    {
        $this->view = json_encode($this->body, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    }

    /**
     * @return array
     */
    private function getHeader($code)
    {
        return ['content-type' => ($code >= 500) ? 'application/vnd.error+json' : 'application/json'];
    }

    /**
     * @param \Exception  $e
     * @param RouterMatch $request
     * @param Status      $status
     *
     * @return array
     */
    private function getResponseBody(\Exception $e, RouterMatch $request, Status $status)
    {
        unset($request);
        $body = ['message' => $status->text];
        if ($status->code >= 500) {
            $body['logref'] = (string) new LogRef($e);
        }

        return $body;
    }
}

application/vnd.error+json error

404 Not Found
content-type: application/vnd.error+json

{
    "message": "Not Found",
    "logref": "ff4dbc05",
    "request": "get page://self/a404",
    "exceptions": "BEAR\\Resource\\Exception\\ResourceNotFoundException(page://self/a404)",
    "file": "/Users/akihito/git/Polidog.Todo/vendor/bear/resource/src/AppAdapter.php(78)"
}

logref.{logref}.log

Wed, 31 May 2017 11:10:58 +0200
get app://self/ (cli-hal-api-app)


Exceptions:

BEAR\Resource\Exception\ResourceNotFoundException(app://self/index) in /Users/akihito/git/Polidog.Todo/vendor/bear/resource/src/AppAdapter.php(78)
Ray\Compiler\Exception\Unbound(Polidog\Todo\Resource\App\Index-) in /Users/akihito/git/Polidog.Todo/vendor/ray/compiler/src/ScriptInjector.php(178)
Ray\Compiler\Exception\ClassNotFound(Polidog\Todo\Resource\App\Index-) in /Users/akihito/git/Polidog.Todo/vendor/ray/compiler/src/ScriptInjector.php(177)

Trace:

#0 BEAR\Resource\AppAdapter->getNotFound(Object(BEAR\Resource\Uri),Object(Ray\Compiler\Exception\Unbound),'Polidog\Todo\Resource\App\Index') in /Users/akihito/git/Polidog.Todo/vendor/bear/resource/src/AppAdapter.php(61)
#1 BEAR\Resource\AppAdapter->get(Object(BEAR\Resource\Uri)) in /Users/akihito/git/Polidog.Todo/vendor/bear/resource/src/Factory.php(52)
#2 BEAR\Resource\Factory->newInstance(Object(BEAR\Resource\Uri)) in /Users/akihito/git/Polidog.Todo/vendor/bear/resource/src/Resource.php(97)
#3 BEAR\Resource\Resource->newInstance(Object(BEAR\Resource\Uri)) in /Users/akihito/git/Polidog.Todo/vendor/bear/resource/src/Resource.php(126)
#4 BEAR\Resource\Resource->uri(Object(BEAR\Resource\Uri)) in /Users/akihito/git/Polidog.Todo/bootstrap/bootstrap.php(20)
#5 require('/Users/akihito/git/Polidog.Todo/bootstrap/bootstrap.php') in /Users/akihito/git/Polidog.Todo/bootstrap/api.php(4)

PHP Variables:

Array
(
    [GET] => Array
        (
        )

    [POST] => Array

var/log/app.log

[2017-05-31 10:31:03] Polidog\Todo.DEBUG: req:"get app://self/" code:404 e:BEAR\Resource\Exception\ResourceNotFoundException(app://self/index) logref:d75761fe [] []
[2017-05-31 10:31:13] Polidog\Todo.DEBUG: req:"get app://self/" code:404 e:BEAR\Resource\Exception\ResourceNotFoundException(app://self/index) logref:d75761fe [] []
[2017-05-31 11:09:39] Polidog\Todo.DEBUG: req:"get app://self/" code:404 e:BEAR\Resource\Exception\ResourceNotFoundException(app://self/index) logref:d75761fe [] []

var/log/context.prod-hal-app.log

Polidog\Todo\Module\App Object
(
    [router] => BEAR\Package\Provide\Router\CliRouter Object
        (
            [router:BEAR\Package\Provide\Router\CliRouter:private] => BEAR\Package\Provide\Router\WebRouter Object
                (
                    [schemeHost:BEAR\Package\Provide\Router\WebRouter:private] => app://self
                    [httpMethodParams:BEAR\Package\Provide\Router\WebRouter:private] => 
// .. 1800 lines...

@Curies annotation supported

"CURIE"s help providing links to resource documentation.
HAL gives you a reserved link relation 'curies' which you can use to hint at the location of resource documentation. See more at http://stateless.co/hal_specification.html

/**
 * @Curies(name="pd", href="api.exmaple.com/docs/{rels}", template=true)
 */
class Index extends ResourceObject
{
    public $body = [
        '_links' => [
            'pd:todo' => ['href' => '/todo'],
            'pd:todos' => ['href' =>'/todos']
        ]
    ];

    public function onGet()
    {
        return $this;
    }
}

bootstrap/api.php get /get /

200 OK
content-type: application/hal+json

{
    "_links": {
        "self": {
            "href": "/index"
        },
        "curies": [
            {
                "href": "api.exmaple.com/docs/{rels}",
                "name": "pd",
                "templated": true
            }
        ],
        "pd:todo": {
            "href": {
                "href": "/todo"
            }
        },
        "pd:todos": {
            "href": {
                "href": "/todos"
            }
        }
    }
}

@ReturnCreatedResource

@ReturnCreatedResource return newly created resource body specified with Location header. . It worked only 201 response and Location URI is valid.

    /**
     * @ReturnCreatedResource
     */
    public function onPost(string $title, NowInterface $now = null) : ResourceObject
    {
        $value = [
            'title' => $title,
            'status' => self::INCOMPLETE,
            'created' => (string) $now,
            'updated' => (string) $now,
        ];
        $this->pdo->perform($this->query['todo_insert'], $value);
        $id = $this->pdo->lastInsertId();
        $this->code = StatusCode::CREATED;
        $this->headers[ResponseHeader::LOCATION] = "/todo?id={$id}";

        return $this;
    }
201 Created
Location: /todo?id=2

{
    "todo": {
        "id": "2",
        "title": "run",
        "status": "1",
        "created": "2017-05-31 12:13:59",
        "updated": "2017-05-31 12:13:59",
        "status_name": "Complete"
    },
    "_links": {
        "self": {
            "href": "/todo?id=2"
        }
    }
}

1.2.5

19 May 21:44
Compare
Choose a tag to compare

This release support BEAR.Resource v2.5.0
https://github.com/bearsunday/BEAR.Resource/releases

OPTIONS method is now supported but disable in prod context.
You can enable it in your prod module. See more at #238

1.2.4

29 Apr 22:46
Compare
Choose a tag to compare

This release improve the performance in view cache.

1.2.3

29 Apr 12:44
Compare
Choose a tag to compare

This release optimize ProdModule.

0.13.2

02 Apr 17:15
Compare
Choose a tag to compare

This release is hotfix to run in php7 as archived project (deprecated)
Test broken but won't fix.

1.2.2

16 Mar 18:56
Compare
Choose a tag to compare
  • [UPDATE] Bootstrap::getApp() takes appDir in third parameter.
  • enable $app cache in cli mode

1.2.1

16 Mar 17:15
Compare
Choose a tag to compare

This release clean up a tmp/ directory on demand to improve performance.

1.2.0

13 Mar 12:52
Compare
Choose a tag to compare

This release add AppInjector #230

1.1.1

28 Feb 12:24
Compare
Choose a tag to compare

This release fix issue #227

1.1.0

28 Feb 08:04
Compare
Choose a tag to compare

This release drop support PHP5.5. #225