Completed
Pull Request — master (#153)
by Robbie
03:00 queued 50s
created

AddonUpdater::update()   D

Complexity

Conditions 9
Paths 16

Size

Total Lines 43
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 4.909
c 0
b 0
f 0
cc 9
eloc 28
nc 16
nop 2
1
<?php
2
3
use Composer\Package\AliasPackage;
4
use Composer\Package\CompletePackage;
5
use Guzzle\Http\Exception\ClientErrorResponseException;
6
use SilverStripe\Elastica\ElasticaService;
7
use Packagist\Api\Result\Package;
8
use Composer\Package\Version\VersionParser;
9
10
/**
11
 * Updates all add-ons from Packagist.
12
 */
13
class AddonUpdater {
14
15
	/**
16
	 * @var PackagistService
17
	 */
18
	private $packagist;
19
20
	/**
21
	 * @var SilverStripe\Elastica\ElasticaService
22
	 */
23
	private $elastica;
24
25
	/**
26
	 * @var ResqueService
27
	 */
28
	private $resque;
29
30
	/**
31
	 * @var SilverStripeVersion[]
32
	 */
33
	private $silverstripes;
34
35
	public function __construct(
36
		PackagistService $packagist,
37
		ElasticaService $elastica,
38
		ResqueService $resque
39
	) {
40
		$this->packagist = $packagist;
41
		$this->elastica = $elastica;
42
		$this->resque = $resque;
43
44
        $this->setSilverStripeVersions(SilverStripeVersion::get());
45
	}
46
47
	/**
48
	 * Updates all add-ons.
49
	 *
50
	 * @param Boolean Clear existing addons before updating them.
51
	 * Will also clear their search index, and cascade the delete for associated data.
52
	 * @param Array Limit to specific addons, using their name incl. vendor prefix.
53
	 */
54
	public function update($clear = false, $limitAddons = null) {
55
		if($clear && !$limitAddons) {
56
			Addon::get()->removeAll();
57
			AddonAuthor::get()->removeAll();
58
			AddonKeyword::get()->removeAll();
59
			AddonLink::get()->removeAll();
60
			AddonVendor::get()->removeAll();
61
			AddonVersion::get()->removeAll();
62
		}
63
64
		// This call to packagist can be expensive. Requests are served from a cache if usePackagistCache() returns true
65
		$cache = SS_Cache::factory('addons');
66
		if($this->usePackagistCache() && $packages = $cache->load('packagist')) {
67
			$packages = unserialize($packages);
68
		} else {
69
			$packages = $this->packagist->getPackages();
70
			$cache->save(serialize($packages), 'packagist');
71
		}
72
		$this->elastica->startBulkIndex();
73
74
		foreach ($packages as $package) {
75
			$name = $package->getName();
76
			$versions = $package->getVersions();
77
78
			if($limitAddons && !in_array($name, $limitAddons)) continue;
79
80
			$addon = Addon::get()->filter('Name', $name)->first();
81
82
			if (!$addon) {
83
				$addon = new Addon();
84
				$addon->Name = $name;
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
85
				$addon->write();
86
			}
87
88
			usort($versions, function ($a, $b) {
89
				return version_compare($a->getVersionNormalized(), $b->getVersionNormalized());
90
			});
91
92
			$this->updateAddon($addon, $package, $versions);
0 ignored issues
show
Compatibility introduced by
$addon of type object<DataObject> is not a sub-type of object<Addon>. It seems like you assume a child class of the class DataObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
93
		}
94
95
		$this->elastica->endBulkIndex();
96
	}
97
98
99
100
	/**
101
	 * Check whether or not we should contact packagist or use a cached version. This allows to speed up the task
102
	 * during development.
103
	 *
104
	 * @return bool
105
	 */
106
	protected function usePackagistCache() {
107
		return Director::isDev();
108
	}
109
110
	private function updateAddon(Addon $addon, Package $package, array $versions) {
111
		if (!$addon->VendorID) {
0 ignored issues
show
Documentation introduced by
The property VendorID does not exist on object<Addon>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
112
			$vendor = AddonVendor::get()->filter('Name', $addon->VendorName())->first();
113
114
			if (!$vendor) {
115
				$vendor = new AddonVendor();
116
				$vendor->Name = $addon->VendorName();
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<AddonVendor>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
117
				$vendor->write();
118
			}
119
120
			$addon->VendorID = $vendor->ID;
0 ignored issues
show
Documentation introduced by
The property VendorID does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
121
		}
122
123
		$addon->Type = str_replace('silverstripe-', '', $package->getType());
0 ignored issues
show
Documentation introduced by
The property Type does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
124
		$addon->Description = $package->getDescription();
0 ignored issues
show
Documentation introduced by
The property Description does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
125
		$addon->Released = strtotime($package->getTime());
0 ignored issues
show
Documentation introduced by
The property Released does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
126
		$addon->Repository = $package->getRepository();
0 ignored issues
show
Documentation introduced by
The property Repository does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
127
		$addon->Downloads = $package->getDownloads()->getTotal();
0 ignored issues
show
Documentation introduced by
The property Downloads does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
128
		$addon->DownloadsMonthly = $package->getDownloads()->getMonthly();
0 ignored issues
show
Documentation introduced by
The property DownloadsMonthly does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
129
		$addon->Favers = $package->getFavers();
0 ignored issues
show
Documentation introduced by
The property Favers does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
130
131
		foreach ($versions as $version) {
132
			$this->updateVersion($addon, $version);
133
		}
134
135
		// If there is no build, then queue one up if the add-on requires
136
		// one.
137
		if (!$addon->BuildQueued) {
0 ignored issues
show
Documentation introduced by
The property BuildQueued does not exist on object<Addon>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
138
			if (!$addon->BuiltAt) {
0 ignored issues
show
Documentation introduced by
The property BuiltAt does not exist on object<Addon>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
139
				$this->resque->queue('first_build', 'BuildAddonJob', array('id' => $addon->ID));
140
				$addon->BuildQueued = true;
0 ignored issues
show
Documentation introduced by
The property BuildQueued does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
141
			} else {
142
				$built = (int) $addon->obj('BuiltAt')->format('U');
143
144
				foreach ($versions as $version) {
145
					if (strtotime($version->getTime()) > $built) {
146
						$this->resque->queue('update', 'BuildAddonJob', array('id' => $addon->ID));
147
						$addon->BuildQueued = true;
0 ignored issues
show
Documentation introduced by
The property BuildQueued does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
148
149
						break;
150
					}
151
				}
152
			}
153
		}
154
155
		$addon->LastUpdated = time();
0 ignored issues
show
Documentation introduced by
The property LastUpdated does not exist on object<Addon>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
156
		$addon->write();
157
	}
158
159
	private function updateVersion(Addon $addon, Version $package) {
160
		$version = null;
161
162
		if ($addon->isInDB()) {
163
			$version = $addon->Versions()->filter('Version', $package->getVersionNormalized())->first();
0 ignored issues
show
Bug introduced by
The method Versions() does not exist on Addon. Did you maybe mean SortedVersions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
164
		}
165
166
		if (!$version) {
167
			$version = new AddonVersion();
168
		}
169
170
		$version->Name = $package->getName();
171
		$version->Type = str_replace('silverstripe-', '', $package->getType());
172
		$version->Description = $package->getDescription();
173
		$version->Released = strtotime($package->getTime());
174
		$keywords = $package->getKeywords();
175
176
		if ($keywords) {
177
			foreach ($keywords as $keyword) {
178
				$keyword = AddonKeyword::get_by_name($keyword);
179
180
				$addon->Keywords()->add($keyword);
0 ignored issues
show
Documentation Bug introduced by
The method Keywords does not exist on object<Addon>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
181
				$version->Keywords()->add($keyword);
182
			}
183
		}
184
185
		$version->Version = $package->getVersionNormalized();
186
		$version->PrettyVersion = $package->getVersion();
187
188
		$stability = VersionParser::parseStability($package->getVersion());
189
		$isDev = $stability === 'dev';
190
		$version->Development = $isDev;
191
192
		$version->SourceType = $package->getSource()->getType();
193
		$version->SourceUrl = $package->getSource()->getUrl();
194
		$version->SourceReference = $package->getSource()->getReference();
195
196
		if($package->getDist()) {
197
			$version->DistType = $package->getDist()->getType();
198
			$version->DistUrl = $package->getDist()->getUrl();
199
			$version->DistReference = $package->getDist()->getReference();
200
			$version->DistChecksum = $package->getDist()->getShasum();
201
		}
202
203
		$version->Extra = $package->getExtra();
204
		$version->Homepage = $package->getHomepage();
205
		$version->License = $package->getLicense();
206
		// $version->Support = $package->getSupport();
207
208
		$addon->Versions()->add($version);
0 ignored issues
show
Bug introduced by
The method Versions() does not exist on Addon. Did you maybe mean SortedVersions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
209
210
		$this->updateLinks($version, $package);
211
		$this->updateCompatibility($addon, $version, $package);
212
		$this->updateAuthors($version, $package);
213
	}
214
215
	private function updateLinks(AddonVersion $version, CompletePackage $package) {
216
		$getLink = function ($name, $type) use ($version) {
217
			$link = null;
218
219
			if ($version->isInDB()) {
220
				$link = $version->Links()->filter('Name', $name)->filter('Type', $type)->first();
0 ignored issues
show
Documentation Bug introduced by
The method Links does not exist on object<AddonVersion>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
221
			}
222
223
			if (!$link) {
224
				$link = new AddonLink();
225
				$link->Name = $name;
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<AddonLink>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
226
				$link->Type = $type;
0 ignored issues
show
Documentation introduced by
The property Type does not exist on object<AddonLink>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
227
			}
228
229
			return $link;
230
		};
231
232
		$types = array(
233
			'require' => 'getRequire',
234
			'require-dev' => 'getRequireDev',
235
			'provide' => 'getProvide',
236
			'conflict' => 'getConflict',
237
			'replace' => 'getReplace'
238
		);
239
240
		foreach ($types as $type => $method) {
241
			if ($linked = $package->$method()) foreach ($linked as $link => $constraint) {
242
				$name = $link;
243
				$addon = Addon::get()->filter('Name', $name)->first();
244
245
				$local = $getLink($name, $type);
246
				$local->Constraint = $constraint;
247
248
				if ($addon) {
249
					$local->TargetID = $addon->ID;
250
				}
251
252
				$version->Links()->add($local);
0 ignored issues
show
Documentation Bug introduced by
The method Links does not exist on object<AddonVersion>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
253
			}
254
		}
255
256
		//to-do api have no method to get this.
257
		/*$suggested = $package->getSuggests();
258
259
		if ($suggested) foreach ($suggested as $package => $description) {
260
			$link = $getLink($package, 'suggest');
261
			$link->Description = $description;
262
263
			$version->Links()->add($link);
264
		}*/
265
	}
266
267
	private function updateCompatibility(Addon $addon, AddonVersion $version, CompletePackage $package) {
268
		$require = null;
269
270
		if($package->getRequire()) foreach ($package->getRequire() as $name => $link) {
0 ignored issues
show
Bug introduced by
The method getRequire() does not exist on Composer\Package\CompletePackage. Did you maybe mean getRequires()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
271
			if((string)$link == 'self.version') continue;
272
273
			if ($name == 'silverstripe/framework') {
274
				$require = $link;
275
				break;
276
			}
277
278
			if ($name == 'silverstripe/cms') {
279
				$require = $link;
280
			}
281
		}
282
283
		if (!$require) {
284
			return;
285
		}
286
287
		$addon->CompatibleVersions()->removeAll();
0 ignored issues
show
Documentation Bug introduced by
The method CompatibleVersions does not exist on object<Addon>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
288
		$version->CompatibleVersions()->removeAll();
0 ignored issues
show
Documentation Bug introduced by
The method CompatibleVersions does not exist on object<AddonVersion>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
289
290
		foreach ($this->getSilverStripeVersions() as $silverStripeVersion) {
291
            /** @var SilverStripeVersion $silverStripeVersion */
292
			try {
293
                if ($silverStripeVersion->getConstraintValidity($require)) {
294
					$addon->CompatibleVersions()->add($silverStripeVersion);
0 ignored issues
show
Documentation Bug introduced by
The method CompatibleVersions does not exist on object<Addon>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
295
					$version->CompatibleVersions()->add($silverStripeVersion);
0 ignored issues
show
Documentation Bug introduced by
The method CompatibleVersions does not exist on object<AddonVersion>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
296
				}
297
			} catch (Exception $e) {
298
				// An exception here shouldn't prevent further updates.
299
				Debug::log($addon->Name . "\t" . $addon->ID . "\t" . $e->getMessage());
0 ignored issues
show
Documentation introduced by
The property Name does not exist on object<Addon>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
300
			}
301
		}
302
	}
303
304
	private function updateAuthors(AddonVersion $version, CompletePackage $package) {
305
		if ($package->getAuthors()) foreach ($package->getAuthors() as $details) {
306
			$author = null;
307
308
			if (!$details->getName() && !$details->getEmail()) {
309
				continue;
310
			}
311
312
			if ($details->getEmail()) {
313
				$author = AddonAuthor::get()->filter('Email', $details->getEmail())->first();
314
			}
315
316
			if (!$author && $details->getHomepage()) {
317
				$author = AddonAuthor::get()
318
					->filter('Name', $details->getName())
319
					->filter('Homepage', $details->getHomepage())
320
					->first();
321
			}
322
323
			if (!$author && $details->getName()) {
324
				$author = AddonAuthor::get()
325
					->filter('Name', $details->getName())
326
					->filter('Versions.Addon.Name', $package->getName())
327
					->first();
328
			}
329
330
			if (!$author) {
331
				$author = new AddonAuthor();
332
			}
333
334
			if($details->getName()) $author->Name = $details->getName();
335
			if($details->getEmail()) $author->Email = $details->getEmail();
336
			if($details->getHomepage()) $author->Homepage = $details->getHomepage();
337
338
			//to-do not supported by API
339
			//if(isset($details['role'])) $author->Role = $details['role'];
340
341
			$version->Authors()->add($author->write());
0 ignored issues
show
Documentation Bug introduced by
The method Authors does not exist on object<AddonVersion>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
342
		}
343
	}
344
345
    /**
346
     * Get the list of SilverStripe versions
347
     *
348
     * @return DataList
349
     */
350
    public function getSilverStripeVersions()
351
    {
352
        return $this->silverstripes;
353
    }
354
355
    /**
356
     * Set the list of SilverStripeVersions
357
     *
358
     * @param  DataList $versions
359
     * @return $this
360
     */
361
    public function setSilverStripeVersions(DataList $versions)
362
    {
363
        $this->silverstripes = $versions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $versions of type object<DataList> is incompatible with the declared type array<integer,object<SilverStripeVersion>> of property $silverstripes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
364
        return $this;
365
    }
366
}
367