InstagramPageExtension::getMediaFromCache()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
1
<?php
2
3
use MetzWeb\Instagram\Instagram as Instagram;
4
5
class InstagramPageExtension extends DataExtension
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
6
{
7
    /**
8
     * @var array
9
     */
10
    private static $casting = [
0 ignored issues
show
Unused Code introduced by
The property $casting is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
11
        'instagramShortcodeHandler' => 'HTMLText',
12
    ];
13
14
    /**
15
     * Gets a list of media from the cache.
16
     *
17
     * @param InstagramAccount $instagramAccount
18
     * @param string $maxID
19
     * @return array|null
20
     */
21
    public static function getMediaFromCache($instagramAccount, $maxID)
22
    {
23
        $cache = SS_Cache::factory('InstagramPage');
24
25
        if (!($result = $cache->load("{$instagramAccount->getField('Title')}_{$maxID}"))) {
26
            return null;
27
        }
28
29
        return unserialize($result);
30
    }
31
32
    /**
33
     * Gets a list of media from Instagram.
34
     *
35
     * @param InstagramAccount $instagramAccount
36
     * @param string $maxID
37
     * @return array|null
38
     */
39
    public static function getMediaFromInstagram($instagramAccount, $maxID)
40
    {
41
        $response = $instagramAccount->getMedia($maxID);
42
43
        if (!$response) {
44
            return null;
45
        }
46
47
        $raw = $response->getRaw();
48
49
        if (!$raw || !array_key_exists('meta', $raw) || $raw['meta']['code'] !== 200) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $raw of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
50
            user_error('Unable to fetch media from Instagram', E_USER_WARNING);
51
            return null;
52
        }
53
54
        return $raw['data'];
55
    }
56
57
    /**
58
     * Updates the cache with media fetched from Instagram.
59
     *
60
     * @param InstagramAccount $instagramAccount
61
     * @param string $maxID
62
     * @param array $media
63
     * @return null
64
     */
65
    public static function updateCachedMedia($instagramAccount, $maxID, $media)
66
    {
67
        $cache = SS_Cache::factory('InstagramPage');
68
        $cache->save(serialize($media), "{$instagramAccount->getField('Title')}_{$maxID}");
69
    }
70
71
    /**
72
     * Gets a list of media from the cache if available. Falls back to making an API request.
73
     *
74
     * @param InstagramAccount $instagramAccount
75
     * @param string $maxID
76
     * @return array|null
77
     */
78
    public static function getMedia($instagramAccount, $maxID) {
79
        // Return media from the cache if it's available.
80
        if ($media = self::getMediaFromCache($instagramAccount, $maxID)) {
81
            return $media;
82
        }
83
84
        // Fetch media from Instagram and cache it.
85
        if ($media = self::getMediaFromInstagram($instagramAccount, $maxID)) {
86
            self::updateCachedMedia($instagramAccount, $maxID, $media);
87
        }
88
89
        return $media;
90
    }
91
92
    /**
93
     * Handler for the `instagram` Shortcode.
94
     *
95
     * @return string|null
96
     */
97
    public static function instagramShortcodeHandler($args, $content = null, $parser = null, $tag)
0 ignored issues
show
Unused Code introduced by
The parameter $content is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $tag is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
98
    {
99
        if (!array_key_exists('username', $args)) {
100
            return null;
101
        }
102
103
        $instagramAccount = InstagramAccount::get()->filter('Title', $args['username'])->First();
104
105
        // Make sure the InstagramAccount is valid and has been authorised.
106
        if (!$instagramAccount || !$instagramAccount->getField('AccessToken')) {
107
            return null;
108
        }
109
110
        $controller = Controller::curr();
111
        $link = $controller->Link();
112
113
        // Valid IDs only have digits and an underscore.
114
        $maxID = preg_replace('/[^\d_]/', '', $controller->getRequest()->getVar('start'));
115
116
        $media = self::getMedia($instagramAccount, $maxID);
0 ignored issues
show
Bug introduced by
It seems like $maxID defined by preg_replace('/[^\\d_]/'...est()->getVar('start')) on line 114 can also be of type array<integer,string>; however, InstagramPageExtension::getMedia() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
117
118
        if (!$media) {
119
            return null;
120
        }
121
122
        // If there are less items returned than the maximum allowed per page,
123
        // we're on the last page, so don't include a 'next' button.
124
        //
125
        // TODO:
126
        // Handle edge case where it's the last page and exactly "items_per_page" are returned.
127
        $loadMoreLink = count($media) < Config::inst()->get('InstagramAccount', 'items_per_page')
128
            ? null
129
            : $link . '?start=' . array_pop((array_slice($media, -1)))['id'];
0 ignored issues
show
Bug introduced by
array_slice($media, -1) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
130
131
        // Make tags iterable in the template.
132
        foreach ($media as &$item) {
133
            $item['tags'] = ArrayList::create(
134
                array_map(function ($tag) {
135
                    return ArrayData::create(['name' => $tag]);
136
                }, $item['tags'])
137
            );
138
        }
139
140
        $data = ArrayData::create([
141
            'loadMoreLink' => $loadMoreLink,
142
            'instagramLink' => "https://www.instagram.com/{$args['username']}"
143
        ]);
144
145
        $data->setField('media', ArrayList::create($media));
146
147
        return $data->renderWith('InstagramPage');
148
    }
149
}
150