Passed
Push — master ( b97db7...1f1fbe )
by Sam
02:23
created

ContentfulSyncController::handleIncomingWebhook()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 26
nc 7
nop 1
1
<?php
2
3
namespace Digia\Lumen\ContentfulSync\Http\Controllers;
4
5
use Digia\Lumen\ContentfulSync\Exceptions\ContentfulSyncException;
6
use Digia\Lumen\ContentfulSync\Http\Middleware\NewRelicMiddleware;
7
use Digia\Lumen\ContentfulSync\Services\AbstractContentfulSyncService;
8
use Illuminate\Http\Request;
9
use Illuminate\Http\Response;
10
use Laravel\Lumen\Routing\Controller;
11
use Nord\Lumen\Contentful\ContentfulService;
12
13
/**
14
 * Handles incoming webhooks from Contentful
15
 *
16
 * @package Digia\Lumen\ContentfulSync\Http\Controllers
17
 */
18
class ContentfulSyncController extends Controller
19
{
20
21
    protected const TOPIC_CONTENT_MANAGEMENT_ASSET_PUBLISH   = 'ContentManagement.Asset.publish';
22
    protected const TOPIC_CONTENT_MANAGEMENT_ASSET_UNPUBLISH = 'ContentManagement.Asset.unpublish';
23
    protected const TOPIC_CONTENT_MANAGEMENT_ASSET_DELETE    = 'ContentManagement.Asset.delete';
24
    protected const TOPIC_CONTENT_MANAGEMENT_ENTRY_PUBLISH   = 'ContentManagement.Entry.publish';
25
    protected const TOPIC_CONTENT_MANAGEMENT_ENTRY_UNPUBLISH = 'ContentManagement.Entry.unpublish';
26
    protected const TOPIC_CONTENT_MANAGEMENT_ENTRY_DELETE    = 'ContentManagement.Entry.delete';
27
28
    /**
29
     * @var ContentfulService
30
     */
31
    private $contentfulService;
32
33
    /**
34
     * @var AbstractContentfulSyncService
35
     */
36
    private $contentfulSyncService;
37
38
    /**
39
     * ContentfulSyncController constructor.
40
     *
41
     * @param ContentfulService             $contentfulService
42
     * @param AbstractContentfulSyncService $contentfulSyncService
43
     */
44
    public function __construct(
45
        ContentfulService $contentfulService,
46
        AbstractContentfulSyncService $contentfulSyncService
47
    ) {
48
        $this->contentfulService     = $contentfulService;
49
        $this->contentfulSyncService = $contentfulSyncService;
50
    }
51
52
    /**
53
     * @param Request $request
54
     *
55
     * @return Response
56
     *
57
     * @throws ContentfulSyncException if the webhook cannot be handled
58
     */
59
    public function handleIncomingWebhook(Request $request): Response
60
    {
61
        // Parse the payload into a Contentful SDK resource object
62
        $resource = $this->contentfulService->getClient()->reviveJson($request->getContent());
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Contentful\Delivery\Client::reviveJson() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
63
64
        // Instrument the request so the middleware can do its job
65
        $contentfulTopic = $this->getContentfulTopic($request);
66
        $request->attributes->set(NewRelicMiddleware::ATTRIBUTE_TOPIC, $contentfulTopic);
67
68
        // Handle different topics differently
69
        switch ($contentfulTopic) {
70
            case self::TOPIC_CONTENT_MANAGEMENT_ASSET_PUBLISH:
71
                $this->contentfulSyncService->publishAsset($request->getContent());
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Digia\Lumen\ContentfulSy...Service::publishAsset() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
72
                break;
73
            case self::TOPIC_CONTENT_MANAGEMENT_ASSET_UNPUBLISH:
74
            case self::TOPIC_CONTENT_MANAGEMENT_ASSET_DELETE:
75
                $this->contentfulSyncService->deleteAsset($resource->getId());
0 ignored issues
show
Bug introduced by
The method getId does only exist in Contentful\Delivery\Asse...ronization\DeletedEntry, but not in Contentful\ResourceArray.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
76
                break;
77
            case self::TOPIC_CONTENT_MANAGEMENT_ENTRY_PUBLISH:
78
                $contentType = $resource->getContentType()->getId();
0 ignored issues
show
Bug introduced by
The method getContentType does only exist in Contentful\Delivery\Dyna...ronization\DeletedEntry, but not in Contentful\Delivery\Asse...ontentful\ResourceArray.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
79
80
                $request->attributes->set(NewRelicMiddleware::ATTRIBUTE_CONTENT_TYPE, $contentType);
81
82
                $this->contentfulSyncService->publishEntry($contentType, $request->getContent());
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, Digia\Lumen\ContentfulSy...Service::publishEntry() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
83
                break;
84
            case self::TOPIC_CONTENT_MANAGEMENT_ENTRY_UNPUBLISH:
85
            case self::TOPIC_CONTENT_MANAGEMENT_ENTRY_DELETE:
86
                $contentType = $resource->getContentType()->getId();
87
88
                $request->attributes->set(NewRelicMiddleware::ATTRIBUTE_CONTENT_TYPE, $contentType);
89
90
                $this->contentfulSyncService->deleteEntry($contentType, $resource->getId());
91
                break;
92
            default:
93
                throw new ContentfulSyncException(sprintf('Unknown topic "%s"', $contentfulTopic));
94
        }
95
96
        return new Response();
97
    }
98
99
    /**
100
     * @param Request $request
101
     *
102
     * @return string
103
     */
104
    private function getContentfulTopic(Request $request): string
105
    {
106
        return $request->header('X-Contentful-Topic', '');
107
    }
108
}
109