Code Monkey home page Code Monkey logo

bear.resource's People

Contributors

apple-x-co avatar bar avatar jingu avatar kazuyauchida avatar koriym avatar kuma-guy avatar kumamidori avatar mackstar avatar madapaja avatar mugeso avatar naokitsuchiya avatar nateabele avatar ryo88c avatar sosuke-ito avatar wand2016 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bear.resource's Issues

JsonSchema attribute support "target=view"

概要

Currently, JsonSchema validation is only performed on the "body" of the ResourceObject, but there is an option to perform validation on the "view" as well.

現在、JsonSchemaのバリデーションをResourceObjectの"body"に対してだけ行っていますが、"view"に対しても行うオプションを用意します。

コード

annotation

/**
 * @JsonSchema(schema="user.json", target="view")
 */

attribute

#[JsonSchema(schema: 'user.json', target: 'view')]

(string) to turn the ResourceObject into a JSON string, and then validate it against the decoded JSON.
(string)でResourceObjectをJSON文字列にして、それをdecodeしたJSONに対してのバリデーションを行います。

実例

例えば、BEAR.SundayのHalレンダラーでレンダリングされるlinkに対してもスキーマを記述することができるようになります。

Throw NotCompiled with Ray/Compiler/ScriptInjector

injector に Injector の代わりに ScriptInjector クラスを利用し、
存在しないリソースをfactoryに渡すと ResourceNotFoundException でなく NotCompiled が throw されるのですがこちらは仕様になりますでしょうか?
(古いですが 1.1.6 時点だと ResourceNotFoundException がthrowされるようです)

version: 1.2.1

失敗するテストを作成すると以下になります

<?php

namespace BEAR\Resource;

use BEAR\Resource\Exception\ResourceNotFoundException;
use Ray\Compiler\ScriptInjector;
use Ray\Di\Injector;

class FactoryTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var Factory
     */
    protected $factory;

    protected function setUp()
    {
        parent::setUp();
//        $injector = new Injector;
        $injector = new ScriptInjector($_ENV['TMP_DIR']);
        $scheme = (new SchemeCollection)
            ->scheme('app')->host('self')->toAdapter(new AppAdapter($injector, 'FakeVendor\Sandbox', 'Resource\App'))
            ->scheme('page')->host('self')->toAdapter(new AppAdapter($injector, 'FakeVendor\Sandbox', 'Resource\Page'))
            ->scheme('prov')->host('self')->toAdapter(new FakeProv)
            ->scheme('nop')->host('self')->toAdapter(new FakeNop);
        $this->factory = new Factory($scheme);
    }

    public function testResourceNotFound()
    {
        $this->setExpectedException(ResourceNotFoundException::class);
        $this->factory->newInstance('page://self/not_found_XXXX');
    }
}

"400 Bad Request" returns when imported Page resource uses its App resource.

ひとまずご報告です。

http://bearsunday.github.io/manuals/1.0/ja/tutorial.html

を参考に、「アプリケーションのインポート」を試していますが、呼び出し元のアプリケーション(A) からインポートしたアプリケーションの Page リソース (B) を利用するとき、その Page リソースが App リソース(C)を利用していると、400 Bad Request が返ってきます。

(A)

<?php

namespace Kilica\Core\Resource\App;

use BEAR\Resource\ResourceObject;
use BEAR\Sunday\Inject\ResourceInject;

class Import extends ResourceObject
{
    use ResourceInject;

    public function onGet()
    {
        // OK
        $this['item'] = $this->resource->get->uri('app://content/item')->eager->request()->body['item'];

        // NG : "400 Bad Request"
        $this['content'] = $this->resource->get->uri('page://content/index')->eager->request()->body['content'];

        return $this;
    }
}

(B) インポートしたアプリケーションの Page リソース

App リソースを $this->resource->get->uri() しようとしている部分を、 $this['content'] = 'New Content' などに変更すると正常に動作します。

<?php

namespace Kilica\Content\Resource\Page;

use BEAR\Resource\ResourceObject;
use BEAR\Sunday\Inject\ResourceInject;

class Index extends ResourceObject
{
    use ResourceInject;

    public function onGet()
    {
        $this['content'] = $this->resource->get->uri('app://content/item')->eager->request();

        return $this;
    }
}

(C) インポートしたアプリケーションの App リソース

<?php
namespace Kilica\Content\Resource\App;

use BEAR\Resource\ResourceObject;

class Item extends ResourceObject
{
    public function onGet()
    {
        $this['item'] = 'New Content';
        return $this;
    }

} 

実行結果

> php bootstrap/api.php get '/import'
400 Bad Request
content-type: application/vnd.error+json
{"message":"Bad Request"}

URI Mapper

UriMapper convert http external URL and internal BEAR.Resource URI.

<?php
/**
 * This file is part of the BEAR.Package package
 *
 * @package BEAR.Package
 * @license http://opensource.org/licenses/bsd-license.php BSD
 */

namespace BEAR\Resource;

interface UriMapperInterface
{
    /**
     * @param $requestUri "/blog/posts"
     *
     * @return string
     */
    public function map($requestUri);

    /**
     * @param string $internalUri
     *
     * @return string
     */
    public function reverseMap($internalUri);
}

Upgrade or independent from Guzzle

The depending guzzle version is 3.3.* now.
On the other hand, the latest guzzle is 3.8.0.

And major libraries such as "aws/sdk" depends on newer version.

So, I suggest that

  • upgrade it
    or
  • remove dependency on it and add it to "suggest" section in composer.json

I want you to correspond to reflection - docblock 4.0 or higher

Conflict occurred in reflection-docblock when installing felixfbecker/language-server

$ composer require felixfbecker/language-server

Using version ^5.4 for felixfbecker/language-server
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Conclusion: don't install felixfbecker/language-server v5.4.2
    - Conclusion: don't install felixfbecker/language-server v5.4.1
    - Conclusion: remove phpdocumentor/reflection-docblock 3.3.2
    - Installation request for felixfbecker/language-server ^5.4 -> satisfiable by felixfbecker/language-server[v5.4.0, v5.4.1, v5.4.2].
    - Conclusion: don't install phpdocumentor/reflection-docblock 3.3.2
    - felixfbecker/language-server v5.4.0 requires phpdocumentor/reflection-docblock ^4.0.0 -> satisfiable by phpdocumentor/reflection-docblock[4.0.0, 4.0.1, 4.1.0, 4.1.1, 4.2.0, 4.3.0].
    - Can only install one of: phpdocumentor/reflection-docblock[4.0.0, 3.3.2].
    - Can only install one of: phpdocumentor/reflection-docblock[4.0.1, 3.3.2].
    - Can only install one of: phpdocumentor/reflection-docblock[4.1.0, 3.3.2].
    - Can only install one of: phpdocumentor/reflection-docblock[4.1.1, 3.3.2].
    - Can only install one of: phpdocumentor/reflection-docblock[4.2.0, 3.3.2].
    - Can only install one of: phpdocumentor/reflection-docblock[4.3.0, 3.3.2].
    - Installation request for phpdocumentor/reflection-docblock (locked at 3.3.2) -> satisfiable by phpdocumentor/reflection-docblock[3.3.2].


Installation failed, reverting ./composer.json to its original content.

Confirm installation version and dependency

$ composer show -i | grep docblock
You are using the deprecated option "installed". Only installed packages are shown by default now. The --all option can be used to show all packages.
phpdocumentor/reflection-docblock  3.3.2      With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is ...

$ composer depends phpdocumentor/reflection-docblock
bear/resource     1.11.3  requires  phpdocumentor/reflection-docblock (^3.1)
phpspec/prophecy  1.8.0   requires  phpdocumentor/reflection-docblock (^2.0|^3.0.2|^4.0)

If the reflection-docblock version of bear/resource is 4.0 or later, it is likely to be resolved.

`key` type error in @JsonSchema.

@JsonSchema をアノテートして実行したところ、以下AnnotationExceptionが発生しました。

Doctrine\\Common\\Annotations\\AnnotationException([Type Error] Attribute \"key\" of @JsonSchema declared on method Chanshige\\BearApp\\Resource\\App\\Sample::onGet() expects a(n) ?string, but got string.)

以下、keyプロパティのアノテーション型指定(?string)が影響しているようです。
https://github.com/bearsunday/BEAR.Resource/blob/1.x/src/JsonSchema/Annotation/JsonSchema.php#L16

final class JsonSchema
{
    /**
     * Json schema body key name
     *
     * @var ?string
     */
    public $key;

エラーを再現した簡単なリポジトリを用意しましたので、ご確認よろしくお願いします🙏
https://github.com/chanshige/bear_sample

JsonSchemaExceptionHandlerInterface doesn't catch JsonException in requests

JsonSchemaExceptionHandlerInterface handles JsonExceptions on ill-formed responses but not on ill-formed requests.

Is this behavior intentional?

Example

For example, in this test case

public function testParameterException()
{
$caughtException = null;
$ro = $this->getRo(FakeUser::class);
try {
$ro->onGet(30, 'invalid gender');
} catch (JsonSchemaException $e) {
$caughtException = $e;
}
$this->assertEmpty($ro->body);
$this->assertInstanceOf(JsonSchemaException::class, $caughtException);
}

we get JsonException when we provide $gender = 'invalid gender' even if we bind a handler to JsonSchemaExceptionHandlerInterface.

I guess this is intentional, because ill-formed requests normally cannot continue and end up with abort. We might need handlers for this if we want to return some error-reason-responses or specify errors in response headers.

Proposal

If this is NOT intentional, we may want to handle JsonExceptions thrown in the request validation here:

public function invoke(MethodInvocation $invocation)
{
/** @var ReflectionMethod $method */
$method = $invocation->getMethod();
/** @var JsonSchema $jsonSchema */
$jsonSchema = $method->getAnnotation(JsonSchema::class);
if ($jsonSchema->params) {
$arguments = $this->getNamedArguments($invocation);
$this->validateRequest($jsonSchema, $arguments);
}
/** @var ResourceObject $ro */
$ro = $invocation->proceed();
if ($ro->code === 200 || $ro->code == 201) {
$this->validateResponse($ro, $jsonSchema);
}
return $ro;
}
private function validateRequest(JsonSchema $jsonSchema, array $arguments)
{
$schemaFile = $this->validateDir . '/' . $jsonSchema->params;
$this->validateFileExists($schemaFile);
$this->validate($arguments, $schemaFile);
}

Although I've got no good idea. Like this? (maybe BC-break):

diff --git a/src/JsonSchema/Interceptor/JsonSchemaInterceptor.php b/src/JsonSchema/Interceptor/JsonSchemaInterceptor.php
index 024a9e4..d3d2113 100644
--- a/src/JsonSchema/Interceptor/JsonSchemaInterceptor.php
+++ b/src/JsonSchema/Interceptor/JsonSchemaInterceptor.php
@@ -63,11 +63,11 @@ final class JsonSchemaInterceptor implements MethodInterceptor
         $method = $invocation->getMethod();
         /** @var JsonSchema $jsonSchema */
         $jsonSchema = $method->getAnnotation(JsonSchema::class);
-        if ($jsonSchema->params) {
-            $arguments = $this->getNamedArguments($invocation);
-            $this->validateRequest($jsonSchema, $arguments);
-        }
         /** @var ResourceObject $ro */
+        $ro = $this->validateRequest($jsonSchema, $invocation);
+        if ($ro->code === 400) {
+            return $ro;
+        }
         $ro = $invocation->proceed();
         if ($ro->code === 200 || $ro->code == 201) {
             $this->validateResponse($ro, $jsonSchema);
@@ -76,11 +76,23 @@ final class JsonSchemaInterceptor implements MethodInterceptor
         return $ro;
     }

-    private function validateRequest(JsonSchema $jsonSchema, array $arguments)
+    private function validateRequest(JsonSchema $jsonSchema, MethodInvocation $invocation)
     {
+        $ro = $invocation->getThis();
+        if (! $jsonSchema->params) {
+            return $ro;
+        }
         $schemaFile = $this->validateDir . '/' . $jsonSchema->params;
         $this->validateFileExists($schemaFile);
-        $this->validate($arguments, $schemaFile);
+        $arguments = $this->getNamedArguments($invocation);
+        try {
+            $this->validate($arguments, $schemaFile);
+        } catch (JsonSchemaException $e) {
+            $ro->code = 400;
+            $this->handler->handle($ro, $e, $schemaFile);
+        }
+
+        return $ro;
     }

     private function validateResponse(ResourceObject $ro, JsonSchema $jsonSchema)

Resource request invoke exception handler

Resource client can have exception handler on each.

code sample:

namespace ExceptionTest {

    use BEAR\Resource\ExceptionHandlerInterface;
    use BEAR\Resource\Request;

    class MyHandler implements ExceptionHandlerInterface
    {
        public function handle(\Exception $e, Request $request)
        {
            return  'handled:' . $request->toUri();
        }
    }
}

namespace ExceptionTest\Resource\Page {

    use BEAR\Resource\ResourceInterface;
    use BEAR\Resource\ResourceObject;
    use ExceptionTest\MyHandler;
    use Ray\Di\Di\Inject;

    class Index extends ResourceObject
    {
        private $resource;

        /**
         * @Inject
         */
        public function __construct(ResourceInterface $resource)
        {
            $this->resource = $resource;
            $this->resource->setExceptionHandler(new MyHandler());
        }

        public function onGet()
        {
            throw new \RuntimeException;
        }
    }
}


$resource = Injector::create([new ResourceModule('ExceptionTest')])->getInstance('BEAR\Resource\ResourceInterface');
$result = $this->resource->get->uri('page://self/index')->eager->request();
// handled:page://self/index

DevInvoker

実行時のログをとる開発用Invoker

ヘッダーに付加する情報は以下の通り。

['x-interceptors'] インターセプター
['x-links'] リソースリンク
['x-execution-time'] 実行時間
['x-memory-usage] 消費メモリ

Fatal error in demo/5.embed.php

デモを実行しようとしたところ、5番目のデモでエラーが発生しました。

php demo/5.embed.php

Fatal error: Cannot redeclare MyVendor\Demo\Resource\App\Weather_IggGcyM::onGet() in /private/var/folders/9q/1jhss6_j32vbq4qjn9krk69c0000gn/T/MyVendor_Demo_Resource_App_News_IggGcyM.php on line 35

生成されていたファイルでなぜか onGet が重複定義されているようです。

<?php

declare (strict_types=1);
namespace MyVendor\Demo\Resource\App;

use Ray\Aop\WeavedInterface;
use Ray\Aop\ReflectiveMethodInvocation as Invocation;
use BEAR\Resource\Annotation\Embed;
use BEAR\Resource\Module\HalModule;
use BEAR\Resource\Module\ResourceModule;
use BEAR\Resource\ResourceInterface;
use BEAR\Resource\ResourceObject;
use Ray\Di\Injector;
class Weather_IggGcyM extends \MyVendor\Demo\Resource\App\News implements WeavedInterface
{
    public $bind;
    public $bindings = [];
    public $methodAnnotations = 'a:2:{s:5:"onGet";a:1:{i:0;O:30:"BEAR\\Resource\\Annotation\\Embed":2:{s:3:"rel";s:7:"weather";s:3:"src";s:15:"/weather{?date}";}}s:11:"setRenderer";a:1:{i:0;O:16:"Ray\\Di\\Di\\Inject":1:{s:8:"optional";b:1;}}}';
    public $classAnnotations = 'a:0:{}';
    private $isAspect = true;
    /**
     * @Embed(rel="weather", src="/weather{?date}")
     */
    public function onGet(string $date) : ResourceObject
    {
        if (!$this->isAspect) {
            $this->isAspect = true;
            return call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args());
        }
        $this->isAspect = false;
        $result = (new Invocation($this, __FUNCTION__, func_get_args(), $this->bindings[__FUNCTION__]))->proceed();
        $this->isAspect = true;
        return $result;
    }
    public function onGet(string $date) : ResourceObject
    {
        if (!$this->isAspect) {
            $this->isAspect = true;
            return call_user_func_array([$this, 'parent::' . __FUNCTION__], func_get_args());
        }
        $this->isAspect = false;
        $result = (new Invocation($this, __FUNCTION__, func_get_args(), $this->bindings[__FUNCTION__]))->proceed();
        $this->isAspect = true;
        return $result;
    }
}

原因がよくわからなかったのですが、再現しないようでしたら却下で大丈夫です。

TypeError : BEAR\Resource\Interceptor\JsonSchemaInterceptor::deepArray():

Bug Report

TypeError : BEAR\Resource\Interceptor\JsonSchemaInterceptor::deepArray(): Argument #1 ($values) must be of type object, null given, called in /Users/akihito/git/BEAR.Resource/src/JsonSchema/Interceptor/JsonSchemaInterceptor.php on line 136

How to reproduce

When the view of ResourceObject is not json. (HTML)

JsonRenderTest fails on PHP 5.5

JsonRenderTest fails because json_encode function returns false.

I can get error message "Recursion detected" when I call json_last_error_msg function after json_encode failed.

Resource represntation with injectrable resource renderer

How to get resource client with JSON render

$modules = [new ResourceModule('Sandbox'), new JsonModule]:
$resource = Injector::create(modules)
  ->getInstance('BEAR\Resource\ResourceInterface');

How to get resource client with Hal render

$modules = [new ResourceModule('Sandbox'), new HalModule]:
$resource = Injector::create(modules)
  ->getInstance('BEAR\Resource\ResourceInterface');

Request resource with resource client

$user = $resource
  ->get
  ->uri('app://self/link/user')
  ->withQuery(['id' => 1])
  ->eager
  ->request();

Get its representation

echo $user;

//    "name": "Aramis",
//    "age": 16,
//    "blog_id": 12,
//    "_links": {
//        "self": {
//            "href": "app://self/link/user?id=1"
//        }
//    }

Get the the content

echo $user[`name`];

// Aramis

Get the the code

echo $user->code

// 200

The resource is rendered in HAL format.

Constructor support for Input class

public function onPost(User $user)

現在このInputクラスUserはプロパティに直接代入されるだけですが
Currently this Input class User is just assigned directly to a property, but

class Person
{
    public $givenName;
    public $familyName;
}

コンストラクタが存在すればコンストラクタをコールするようにします。
Make the constructor call the constructor if one exists.

PHP8なら名前付き引数です。PHP7なら順序の引数になってしまいます。
In PHP8, they are named arguments; in PHP7, they are ordinal arguments.

class PersonConstructor
{
    public $givenName;
    public $familyName;

    public function __construct(string $givenName, string $familyName)
    {
        $this->givenName = $givenName;
        $this->familyName = $familyName;
    }
}

webの入力とphpの入力をブリッジするこのタイミングでの入力値の追加/変更も行えます。
You can also add/change input values at this time to bridge web input and php input.

class PersonConstructor
{
    public $givenName;
    public $familyName;
    public $fullName;

    public function __construct(string $givenName, string $familyName)
    {
        $this->givenName = $givenName;
        $this->familyName = $familyName;
        $this->fullName = $givenName . ' ' . $familyName;
    }
}

PSR0 compliance for resource object

before:

namespace {Namespace}\Resource\Page;

class News extends ResourceObject
{

after:

namespace {Vendor}\{Namespace}\Resource\Page;

class News extends ResourceObject
{

Adapter\Page is never used.

Because Adapter\App is used for page scheme in Module/SchemeCollectionProvider.

I also searched Adapter\Page in BEAR.Sunday and BEAR.Resource, however, couldn't find that.
So, it seems Adapter\Page is never used, at least, in BEAR Sunday Project.

onProvides Signal parameter

Attach ProvidesParam signal parameter to resource client.

$injector = Injector::create([new ResourceModule('Sandbox')]);
$resource = 
  $injector->getInstance('BEAR\Resource\ResourceInterface');

$resource->attachParamProvider('*', new OnProvidesParam);

A parameter is passed by Provides method if consumer does't pass and method has no default value in method signature.

class Post
{
    public function onPost($date)
    {
        // $date was passed by onProvidesDate method.
    }

    public function onProvidesDate()
    {
        return date(DATE_RFC822);
    }
}

Parameter is injected by Provides{$varName} method in run time. Consumer and method has no responsibility to prepare parameter. It's easy for testing.

ResourceObjectの引数のcastについて

  • 質問: 下記のとおりですが、php bin/app.php get '/weekday?year=2001&month=1&day='のようなアクセスがBOTアクセスにより発生している環境がありまして、対処方法を検討しています。可能であれば400エラーになってくれるとありがたいですが、どのように対応するべきでしょうか?
  • https://bearsunday.github.io/manuals/1.0/ja/tutorial.html のコード参考にしています
$(cat << 'EOF' > src/Resource/App/Weekday.php
<?php

declare(strict_types=1);

namespace MyVendor\Weekday\Resource\App;

use BEAR\Resource\ResourceObject;
use DateTimeImmutable;

class Weekday extends ResourceObject
{
    public function onGet(int $year, int $month, int $day): static
    {
        $dateTime = DateTimeImmutable::createFromFormat('Y-m-d', "$year-$month-$day");
        $weekday = $dateTime->format('D');
        $this->body = ['weekday' => $weekday];

        return $this;
    }
}
EOF
)


# 200 OK: 想定通りです。問題ありません。
php bin/app.php get '/weekday?year=2001&month=1&day=1'

# 400 Bad Request: 想定通りです。問題ありません。
php bin/app.php get '/weekday?year=2001'

# 500 Internal Server Errorでなく、400 Bad Requestにしたいです
php bin/app.php get '/weekday?year=2001&month=1&day='
500 Internal Server Error
content-type: application/vnd.error+json

{
    "message": "Internal Server Error",
    "logref": "87cb1b89",
    "request": "get app://self/weekday?year=2001&month=1&day=",
    "exceptions": "ErrorException(MyVendor\\Weekday\\Resource\\App\\Weekday::onGet(): Argument #3 ($day) must be of type int, string given, called in /Users/adachi/tmp/MyVendor.Weekday/vendor/bear/resource/src/Invoker.php on line 40)",
    "file": "/Users/adachi/tmp/MyVendor.Weekday/src/Resource/App/Weekday.php(12)"
}

Head method returns no contents but same hearder as GET

onHead method, primary used In HEAD request if resource object have 'onHead' method.
or 'onGet' method with no content returns if resource object has onGet method.

headリクエストをした時にonHeadメソッドがあればそれが優先され使われ、無い場合は次にonGetメソッドがあればそのメソッドを実行してbodyを消去し返します。

MethodNotAllowed

ReflectionException is thrown when method is not exists.
Should be MethodNotAllowed exception.

How do we call this software ?

We are wondering what would be a good name for this software.

In the beginning, we called it "Service layer framework".
And now "Hypermedia library", but still wondering if maybe we can have another and more proper name.

このソフトは何と呼ぶのが適切でしょうか?

Question one: Which is better: "framework" or "library" ?
Question two: What would be a good and fitting name for this software ?

Resource Adapter interface extends ProviderInterface

  • A resource adapter is not resource object
  • A resource adapter is factory class of specific scheme's new resource object instance
  • A resource adapter should implements BEAR\Resource\ProviderInterface
  • A resource adapter creates new instance by URI
interface ProviderInterface
{
    /**
     * Return new resource object
     *
     * @param string $uri
     *
     * @return ResourceObject
     */
    public function get($uri);
}

@Embed resource

@Embedアノテーションを使って外部のリソースを自身のbodyに埋め込みます。

@Embed annotation makes embedding resource easier.

use BEAR\Resource\ResourceObject;
use BEAR\Resource\Annotation\Embed;

class Birds extends ResourceObject
{
    /**
     * @Embed(rel="bird1", src="app://self/bird/canary")
     * @Embed(rel="bird2", src="app://self/bird/sparrow{?id}")
     */
    public function onGet($id)
    {
        return $this;
    }
}

is equivalent of

use BEAR\Resource\ResourceObject;
use BEAR\Resource\ResourceInterface;

class Birds extends ResourceObject
{
    public function __construct(ResourceInterface $resource)
    {
        $this->resource = $resource;
    }

    public function onGet($id)
    {
        $this['bird1'] = $this->resource
            ->get
            ->uri('app://self/bird/canary')
            ->request();

        $this['bird2'] = $this->resource
            ->get
            ->uri('app://self/bird/sparrow')
            ->withQuery(['id' => $id])
            ->request();

        return $this;
    }
}

Please pay attention what is embed is a Request, not a result of request
You can modify query parameter after embedded.

use BEAR\Resource\ResourceObject;
use BEAR\Resource\Annotation\Embed;

class Birds extends ResourceObject
{
    /**
     * @Embed(rel="bird1", src="app://self/bird/canary")
     * @Embed(rel="bird2", src="app://self/bird/sparrow{?id}")
     */
    public function onGet($id, $userId)
    {
        // ....
        $this['bird2']->withQuery(['id' => $userId];
        // or add query parameter
        $this['bird2']->addQuery(['option' => 'yes'];
    }
}

@Embed makes not only code more readable and intention clear but also helps for optimization in compile and enable to draw the resource dependency graph without run.

You see the analogy between this and some tag in HTML like <iframe src=$url> or <img src=$url>. The resource embed external resource to its own.

"web" API scheme

new scheme: web

"web" scheme resource enable to access WEB API more BEAR.Resource native and easier.

client

$this->resource
    ->post
    ->uri('web://{service}/{resource}')
    ->withQuery('title' => $title)
    ->eager
    ->request();

config
{$appDir}/Resource/Web/{service}.php

<?php

return [
    'baseUrl' => 'http://httpbin.org/',
    'operations' => [
        'POST:{resource}' => [
            'httpMethod' => 'POST',
            'uri' => '/post',
            'responseModel' => 'getResponse',
            'parameters' => [
                'title' => [
                    'type' => 'string',
                    'location' => 'postField'
                ]
            ],
            '_link' => [
                'new_post' => 'app://self/new_post/?{title}'
            ]
        ]
    ],
    'models' => [
        'getResponse' => [
            'type' => 'object',
            'additionalProperties' => [
                'location' => 'json'
            ]
        ]
    ]
];

See more for config https://github.com/guzzle/guzzle-services

Request::toUriWithMethod()

Request::toUriWithMethod()をメソッドを付加したURI表現
ex) get app://self/posts/

Request::toUri()はリクエストメソッドを除いたURI表現
ex) app://self/posts/

Resource meta infomation iterator

This iterator reveales resource availability and its option.

/** @var $resource \BEAR\Resource\Resource */
foreach ($resource as $meta) {
    var_dump($meta);
}
// class BEAR\Resource\Meta#271 (4) {
//  public $uri =>
//  string(26) "app://self/restbucks/order"
//  public $options =>
//  class BEAR\Resource\Options#209 (2) {
//    public $allow =>
//    array(2) {
//      [0] =>
//      string(3) "get"
//      [1] =>
//      string(4) "post"
//    }
//    public $params =>
//    array(1) {
//      [0] =>
//      class BEAR\Resource\Params#210 (3) {
//        public $method =>
//        string(4) "post"
//        public $required =>
//        array(1) {
//          [0] =>
//          string(5) "drink"
//        }
//        public $optional =>
//        array(0) {
//        }
//      }
//    }
//  }

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.