{"action":"created","comment":{"url":"https://api.github.com/repos/api-platform/docs/pulls/comments/82398924","pull_request_review_id":3308210,"id":82398924,"diff_hunk":"@@ -0,0 +1,164 @@\n+# Extensions\n+\n+API Platform Core provides a system to extends queries on items and collections readings.\n+You can create custom extension that fit your needs.\n+\n+## Custom Extension\n+\n+If Doctrine ORM support is enabled, adding extension is as easy as registering a service in your `app/config/services.yml` file and create the extension you need.\n+\n+Custom extension can be written by implementing the `ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryCollectionExtensionInterface`\n+and / or the `ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryItemExtensionInterface`\n+interfaces, depending on your whether you asking for a collection of items or just an item.\n+\n+If you use [custom data providers](data-providers.md), they must support extensions and be aware of active extensions to work\n+properly.\n+\n+## Filter upon the current user\n+\n+In the following example, we will see how to always get the offers owned by the current user. We will set up an exception, whenever the user possesses the `ROLE_ADMIN`.\n+Given these two entities :\n+\n+```php\n+<?php\n+// src/AppBundle/Entity/User.php\n+\n+namespace AppBundle\\Entity;\n+\n+use ApiPlatform\\Core\\Annotation\\ApiResource;\n+\n+/**\n+ * @ApiResource()\n+ */\n+class User\n+{\n+    // ...\n+}\n+\n+```\n+\n+```php\n+<?php\n+// src/AppBundle/Entity/Offer.php\n+\n+namespace AppBundle\\Entity;\n+\n+use ApiPlatform\\Core\\Annotation\\ApiResource;\n+\n+/**\n+ * @ApiResource()\n+ */\n+class Offer\n+{\n+   /**\n+     * @var User\n+     * @ORM\\ManyToOne(targetEntity=\"User\")\n+     */\n+    private $user;\n+\n+    //...\n+}\n+\n+```\n+\n+```php\n+// src/AppBundle/Doctrine/ORM/Extension/CurrentUserExtension.php\n+<?php\n+\n+namespace AppBundle\\Doctrine\\ORM\\Extension;\n+\n+use ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryCollectionExtensionInterface;\n+use ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryItemExtensionInterface;\n+use ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Util\\QueryNameGeneratorInterface;\n+use ApiPlatform\\Core\\Metadata\\Property\\Factory\\PropertyMetadataFactoryInterface;\n+use ApiPlatform\\Core\\Metadata\\Property\\Factory\\PropertyNameCollectionFactoryInterface;\n+use AppBundle\\Entity\\Offer;\n+use AppBundle\\Entity\\User;\n+use Doctrine\\ORM\\QueryBuilder;\n+use Doctrine\\ORM\\Query\\Expr;\n+use Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface;\n+use Symfony\\Component\\Security\\Core\\Authorization\\AuthorizationChecker;\n+\n+final class CurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface\n+{\n+    private $authorizationChecker;\n+    private $propertyNameCollectionFactory;\n+    private $propertyMetadataFactory;\n+    private $token;\n+\n+    public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, TokenStorageInterface $token, AuthorizationChecker $checker)\n+    {\n+        $this->propertyMetadataFactory = $propertyMetadataFactory;\n+        $this->propertyNameCollectionFactory = $propertyNameCollectionFactory;\n+        $this->token = $token;\n+        $this->authorizationChecker = $checker;\n+    }\n+\n+    /**\n+     * {@inheritdoc}\n+     */\n+    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)\n+    {\n+        $this->addWhere($queryBuilder, $resourceClass);\n+    }\n+\n+    /**\n+     * {@inheritdoc}\n+     */\n+    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null)\n+    {\n+        $this->addWhere($queryBuilder, $resourceClass);\n+    }\n+\n+    /**\n+     * Add where condition\n+     *\n+     * @param QueryBuilder $queryBuilder\n+     * @param string       $resourceClass\n+     */\n+    private function addWhere(QueryBuilder $queryBuilder, string $resourceClass)\n+    {\n+        if (Offer::class !== $resourceClass || $this->authorizationChecker->isGranted('ROLE_ADMIN')) {\n+            return;\n+        }\n+\n+        $classMetadata = $queryBuilder->getEntityManager()->getClassMetadata($resourceClass);\n+        $user = $this->token->getToken()->getUser();","path":"core/extensions.md","position":126,"original_position":126,"commit_id":"0d37ad7a613812e11cd62aeb827112637316d768","original_commit_id":"0d37ad7a613812e11cd62aeb827112637316d768","user":{"login":"dunglas","id":57224,"avatar_url":"https://avatars.githubusercontent.com/u/57224?v=3","gravatar_id":"","url":"https://api.github.com/users/dunglas","html_url":"https://github.com/dunglas","followers_url":"https://api.github.com/users/dunglas/followers","following_url":"https://api.github.com/users/dunglas/following{/other_user}","gists_url":"https://api.github.com/users/dunglas/gists{/gist_id}","starred_url":"https://api.github.com/users/dunglas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dunglas/subscriptions","organizations_url":"https://api.github.com/users/dunglas/orgs","repos_url":"https://api.github.com/users/dunglas/repos","events_url":"https://api.github.com/users/dunglas/events{/privacy}","received_events_url":"https://api.github.com/users/dunglas/received_events","type":"User","site_admin":false},"body":"I think you should test if `$user` is an instance of `User` because IIRC Symfony will return the string `'anon.'` when the user isn't logged in.","created_at":"2016-10-07T14:23:42Z","updated_at":"2016-10-07T14:23:42Z","html_url":"https://github.com/api-platform/docs/pull/120#discussion_r82398924","pull_request_url":"https://api.github.com/repos/api-platform/docs/pulls/120","_links":{"self":{"href":"https://api.github.com/repos/api-platform/docs/pulls/comments/82398924"},"html":{"href":"https://github.com/api-platform/docs/pull/120#discussion_r82398924"},"pull_request":{"href":"https://api.github.com/repos/api-platform/docs/pulls/120"}}},"pull_request":{"url":"https://api.github.com/repos/api-platform/docs/pulls/120","id":88431432,"html_url":"https://github.com/api-platform/docs/pull/120","diff_url":"https://github.com/api-platform/docs/pull/120.diff","patch_url":"https://github.com/api-platform/docs/pull/120.patch","issue_url":"https://api.github.com/repos/api-platform/docs/issues/120","number":120,"state":"open","locked":false,"title":"Add documentation about doctrine query extensions","user":{"login":"GregoireHebert","id":878701,"avatar_url":"https://avatars.githubusercontent.com/u/878701?v=3","gravatar_id":"","url":"https://api.github.com/users/GregoireHebert","html_url":"https://github.com/GregoireHebert","followers_url":"https://api.github.com/users/GregoireHebert/followers","following_url":"https://api.github.com/users/GregoireHebert/following{/other_user}","gists_url":"https://api.github.com/users/GregoireHebert/gists{/gist_id}","starred_url":"https://api.github.com/users/GregoireHebert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GregoireHebert/subscriptions","organizations_url":"https://api.github.com/users/GregoireHebert/orgs","repos_url":"https://api.github.com/users/GregoireHebert/repos","events_url":"https://api.github.com/users/GregoireHebert/events{/privacy}","received_events_url":"https://api.github.com/users/GregoireHebert/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-10-07T12:42:43Z","updated_at":"2016-10-07T14:31:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6ad088a2db4f6263a0a8fa17e9bf1518a7b2e076","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/api-platform/docs/pulls/120/commits","review_comments_url":"https://api.github.com/repos/api-platform/docs/pulls/120/comments","review_comment_url":"https://api.github.com/repos/api-platform/docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/api-platform/docs/issues/120/comments","statuses_url":"https://api.github.com/repos/api-platform/docs/statuses/0d37ad7a613812e11cd62aeb827112637316d768","head":{"label":"GregoireHebert:master","ref":"master","sha":"0d37ad7a613812e11cd62aeb827112637316d768","user":{"login":"GregoireHebert","id":878701,"avatar_url":"https://avatars.githubusercontent.com/u/878701?v=3","gravatar_id":"","url":"https://api.github.com/users/GregoireHebert","html_url":"https://github.com/GregoireHebert","followers_url":"https://api.github.com/users/GregoireHebert/followers","following_url":"https://api.github.com/users/GregoireHebert/following{/other_user}","gists_url":"https://api.github.com/users/GregoireHebert/gists{/gist_id}","starred_url":"https://api.github.com/users/GregoireHebert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GregoireHebert/subscriptions","organizations_url":"https://api.github.com/users/GregoireHebert/orgs","repos_url":"https://api.github.com/users/GregoireHebert/repos","events_url":"https://api.github.com/users/GregoireHebert/events{/privacy}","received_events_url":"https://api.github.com/users/GregoireHebert/received_events","type":"User","site_admin":false},"repo":{"id":70233872,"name":"docs","full_name":"GregoireHebert/docs","owner":{"login":"GregoireHebert","id":878701,"avatar_url":"https://avatars.githubusercontent.com/u/878701?v=3","gravatar_id":"","url":"https://api.github.com/users/GregoireHebert","html_url":"https://github.com/GregoireHebert","followers_url":"https://api.github.com/users/GregoireHebert/followers","following_url":"https://api.github.com/users/GregoireHebert/following{/other_user}","gists_url":"https://api.github.com/users/GregoireHebert/gists{/gist_id}","starred_url":"https://api.github.com/users/GregoireHebert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GregoireHebert/subscriptions","organizations_url":"https://api.github.com/users/GregoireHebert/orgs","repos_url":"https://api.github.com/users/GregoireHebert/repos","events_url":"https://api.github.com/users/GregoireHebert/events{/privacy}","received_events_url":"https://api.github.com/users/GregoireHebert/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/GregoireHebert/docs","description":"API Platform documentation","fork":true,"url":"https://api.github.com/repos/GregoireHebert/docs","forks_url":"https://api.github.com/repos/GregoireHebert/docs/forks","keys_url":"https://api.github.com/repos/GregoireHebert/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GregoireHebert/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GregoireHebert/docs/teams","hooks_url":"https://api.github.com/repos/GregoireHebert/docs/hooks","issue_events_url":"https://api.github.com/repos/GregoireHebert/docs/issues/events{/number}","events_url":"https://api.github.com/repos/GregoireHebert/docs/events","assignees_url":"https://api.github.com/repos/GregoireHebert/docs/assignees{/user}","branches_url":"https://api.github.com/repos/GregoireHebert/docs/branches{/branch}","tags_url":"https://api.github.com/repos/GregoireHebert/docs/tags","blobs_url":"https://api.github.com/repos/GregoireHebert/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GregoireHebert/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GregoireHebert/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/GregoireHebert/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GregoireHebert/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/GregoireHebert/docs/languages","stargazers_url":"https://api.github.com/repos/GregoireHebert/docs/stargazers","contributors_url":"https://api.github.com/repos/GregoireHebert/docs/contributors","subscribers_url":"https://api.github.com/repos/GregoireHebert/docs/subscribers","subscription_url":"https://api.github.com/repos/GregoireHebert/docs/subscription","commits_url":"https://api.github.com/repos/GregoireHebert/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/GregoireHebert/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/GregoireHebert/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/GregoireHebert/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/GregoireHebert/docs/contents/{+path}","compare_url":"https://api.github.com/repos/GregoireHebert/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GregoireHebert/docs/merges","archive_url":"https://api.github.com/repos/GregoireHebert/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GregoireHebert/docs/downloads","issues_url":"https://api.github.com/repos/GregoireHebert/docs/issues{/number}","pulls_url":"https://api.github.com/repos/GregoireHebert/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/GregoireHebert/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/GregoireHebert/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GregoireHebert/docs/labels{/name}","releases_url":"https://api.github.com/repos/GregoireHebert/docs/releases{/id}","deployments_url":"https://api.github.com/repos/GregoireHebert/docs/deployments","created_at":"2016-10-07T09:40:07Z","updated_at":"2016-09-27T21:10:59Z","pushed_at":"2016-10-07T12:40:21Z","git_url":"git://github.com/GregoireHebert/docs.git","ssh_url":"git@github.com:GregoireHebert/docs.git","clone_url":"https://github.com/GregoireHebert/docs.git","svn_url":"https://github.com/GregoireHebert/docs","homepage":"https://api-platform.com/doc/","size":1170,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"api-platform:master","ref":"master","sha":"b0363937337cac86f9dc73ee7a95e1c6ec6d918f","user":{"login":"api-platform","id":13420081,"avatar_url":"https://avatars.githubusercontent.com/u/13420081?v=3","gravatar_id":"","url":"https://api.github.com/users/api-platform","html_url":"https://github.com/api-platform","followers_url":"https://api.github.com/users/api-platform/followers","following_url":"https://api.github.com/users/api-platform/following{/other_user}","gists_url":"https://api.github.com/users/api-platform/gists{/gist_id}","starred_url":"https://api.github.com/users/api-platform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/api-platform/subscriptions","organizations_url":"https://api.github.com/users/api-platform/orgs","repos_url":"https://api.github.com/users/api-platform/repos","events_url":"https://api.github.com/users/api-platform/events{/privacy}","received_events_url":"https://api.github.com/users/api-platform/received_events","type":"Organization","site_admin":false},"repo":{"id":38251565,"name":"docs","full_name":"api-platform/docs","owner":{"login":"api-platform","id":13420081,"avatar_url":"https://avatars.githubusercontent.com/u/13420081?v=3","gravatar_id":"","url":"https://api.github.com/users/api-platform","html_url":"https://github.com/api-platform","followers_url":"https://api.github.com/users/api-platform/followers","following_url":"https://api.github.com/users/api-platform/following{/other_user}","gists_url":"https://api.github.com/users/api-platform/gists{/gist_id}","starred_url":"https://api.github.com/users/api-platform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/api-platform/subscriptions","organizations_url":"https://api.github.com/users/api-platform/orgs","repos_url":"https://api.github.com/users/api-platform/repos","events_url":"https://api.github.com/users/api-platform/events{/privacy}","received_events_url":"https://api.github.com/users/api-platform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/api-platform/docs","description":"API Platform documentation","fork":false,"url":"https://api.github.com/repos/api-platform/docs","forks_url":"https://api.github.com/repos/api-platform/docs/forks","keys_url":"https://api.github.com/repos/api-platform/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/api-platform/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/api-platform/docs/teams","hooks_url":"https://api.github.com/repos/api-platform/docs/hooks","issue_events_url":"https://api.github.com/repos/api-platform/docs/issues/events{/number}","events_url":"https://api.github.com/repos/api-platform/docs/events","assignees_url":"https://api.github.com/repos/api-platform/docs/assignees{/user}","branches_url":"https://api.github.com/repos/api-platform/docs/branches{/branch}","tags_url":"https://api.github.com/repos/api-platform/docs/tags","blobs_url":"https://api.github.com/repos/api-platform/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/api-platform/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/api-platform/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/api-platform/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/api-platform/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/api-platform/docs/languages","stargazers_url":"https://api.github.com/repos/api-platform/docs/stargazers","contributors_url":"https://api.github.com/repos/api-platform/docs/contributors","subscribers_url":"https://api.github.com/repos/api-platform/docs/subscribers","subscription_url":"https://api.github.com/repos/api-platform/docs/subscription","commits_url":"https://api.github.com/repos/api-platform/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/api-platform/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/api-platform/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/api-platform/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/api-platform/docs/contents/{+path}","compare_url":"https://api.github.com/repos/api-platform/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/api-platform/docs/merges","archive_url":"https://api.github.com/repos/api-platform/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/api-platform/docs/downloads","issues_url":"https://api.github.com/repos/api-platform/docs/issues{/number}","pulls_url":"https://api.github.com/repos/api-platform/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/api-platform/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/api-platform/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/api-platform/docs/labels{/name}","releases_url":"https://api.github.com/repos/api-platform/docs/releases{/id}","deployments_url":"https://api.github.com/repos/api-platform/docs/deployments","created_at":"2015-06-29T14:19:34Z","updated_at":"2016-09-27T21:10:59Z","pushed_at":"2016-10-07T14:13:35Z","git_url":"git://github.com/api-platform/docs.git","ssh_url":"git@github.com:api-platform/docs.git","clone_url":"https://github.com/api-platform/docs.git","svn_url":"https://github.com/api-platform/docs","homepage":"https://api-platform.com/doc/","size":1272,"stargazers_count":23,"watchers_count":23,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":43,"mirror_url":null,"open_issues_count":11,"forks":43,"open_issues":11,"watchers":23,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/api-platform/docs/pulls/120"},"html":{"href":"https://github.com/api-platform/docs/pull/120"},"issue":{"href":"https://api.github.com/repos/api-platform/docs/issues/120"},"comments":{"href":"https://api.github.com/repos/api-platform/docs/issues/120/comments"},"review_comments":{"href":"https://api.github.com/repos/api-platform/docs/pulls/120/comments"},"review_comment":{"href":"https://api.github.com/repos/api-platform/docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/api-platform/docs/pulls/120/commits"},"statuses":{"href":"https://api.github.com/repos/api-platform/docs/statuses/0d37ad7a613812e11cd62aeb827112637316d768"}}}}
{"actor":{"display_login":"dunglas"}}