Completed
Push — develop ( 9a607f...a83719 )
by
unknown
07:31
created

Node::getChildren()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @license MIT
7
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
8
 */
9
  
10
/** */
11
namespace Core\Entity\Tree;
12
13
use Core\Entity\Collection\ArrayCollection;
14
use Core\Entity\EntityTrait;
15
use Core\Entity\IdentifiableEntityTrait;
16
use Doctrine\Common\Collections\Collection;
17
use \Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
18
19
/**
20
 * base class for trees.
21
 *
22
 * @ODM\MappedSuperclass
23
 * @author Mathias Gelhausen <[email protected]>
24
 * @since 0.29
25
 */
26
class Node implements NodeInterface
27
{
28
    use EntityTrait, IdentifiableEntityTrait;
29
30
    /**
31
     * Name of this item.
32
     *
33
     * @ODM\Field(type="string")
34
     * @var string
35
     */
36
    protected $name;
37
38
    /**
39
     * Value of this item.
40
     *
41
     * Used in select form elements.
42
     *
43
     * @ODM\Field(type="string")
44
     * @var string
45
     */
46
    protected $value;
47
48
    /**
49
     * Order priority.
50
     *
51
     * @ODM\Field(type="int")
52
     * @var int
53
     */
54
    protected $priority = 0;
55
56
    /**
57
     * Child nodes.
58
     *
59
     * @ODM\ReferenceMany(discriminatorField="_entity", storeAs="dbRef", strategy="set", sort={"priority"="asc"}, cascade="all", orphanRemoval="true")
60
     * @var Collection
61
     */
62
    protected $children;
63
64
    /**
65
     * Parent node.
66
     *
67
     * @ODM\ReferenceOne(discriminatorField="_entity", storeAs="dbRef", nullable="true")
68
     * @var
69
     */
70
    protected $parent;
71
72
    final public static function filterValue($value)
73
    {
74
        $value = mb_strtolower($value);
75
        $value = str_replace(['ä', 'ö', 'ü', 'ß'], ['ae', 'oe', 'ue', 'ss'], $value);
76
        $value = preg_replace(['~[^a-z0-9]~', '~__+~'], '_', $value);
77
78
        return $value;
79
    }
80
81
    /**
82
     * Creates a new Tree item.
83
     *
84
     * @param null|string $name
85
     * @param null|string $value
86
     * @param int  $priority
87
     */
88
    public function __construct($name = null, $value = null, $priority = 0)
89
    {
90
        if (null !== $name) {
91
            $this->setName($name);
92
            $this->setValue($value);
93
            $this->setPriority($priority);
94
        }
95
    }
96
97
    /**
98
     * Set the name.
99
     *
100
     * @param string $name
101
     *
102
     * @return self
103
     * @throws \InvalidArgumentException if $name is empty.
104
     */
105
    public function setName($name)
106
    {
107
        if (!$name) {
108
            throw new \InvalidArgumentException('Name must not be empty.');
109
        }
110
111
        $this->name = (string) $name;
112
113
        return $this;
114
    }
115
116
    public function getName()
117
    {
118
        return $this->name;
119
    }
120
121
    /**
122
     * Set the value.
123
     *
124
     * Used in form selects.
125
     *
126
     * @param string $value
127
     *
128
     * @return self
129
     * @throws \InvalidArgumentException if $value AND {@link name} are empty.
130
     */
131
    public function setValue($value)
132
    {
133
        if (!$value) {
134
            if (!$this->getName()) {
135
                throw new \InvalidArgumentException('Value must not be empty.');
136
            }
137
            $value = self::filterValue($this->getName());
138
        }
139
140
        $this->value = (string) $value;
141
142
        return $this;
143
    }
144
145
    public function getValue()
146
    {
147
        if (!$this->value) {
148
            $this->setValue(null);
149
        }
150
151
        return $this->value;
152
    }
153
154
    public function getValueWithParents($withRoot = false, $useNames = false)
155
    {
156
        $parts = [ ($useNames ? $this->getName() : $this->getValue()) ];
157
        $item = $this;
158
159
        while ($item = $item->getParent()) {
160
            $parts[] = $useNames ? $item->getName() : $item->getValue();
161
        }
162
163
        if (!$withRoot) {
164
            array_pop($parts); // No root node.
165
        }
166
167
        $parts = array_reverse($parts);
168
        $value = join(($useNames ? ' | ' : '-'), $parts);
169
170
        return $value;
171
    }
172
173
    public function getNameWithParents($withRoot = false)
174
    {
175
        return $this->getValueWithParents($withRoot, true);
176
    }
177
178
    public function setPriority($priority)
179
    {
180
        $this->priority = (int) $priority;
181
182
        return $this;
183
    }
184
185
    public function getPriority()
186
    {
187
        return $this->priority;
188
    }
189
190
    public function setChildren(Collection $children)
191
    {
192
        $this->children = $children;
193
194
        /* @var NodeInterface $child */
195
        foreach ($children as $child) {
196
            $child->setParent($this);
197
        }
198
199
        return $this;
200
    }
201
202
    public function getChildren()
203
    {
204
        if (!$this->children) {
205
            $this->setChildren(new ArrayCollection());
206
        }
207
208
        return $this->children;
209
    }
210
211
    public function hasChildren()
212
    {
213
        return (bool) $this->getChildren()->count();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Traversable as the method count() does only exist in the following implementations of said interface: Applications\Form\ApplicationsFilter, Applications\Form\Apply, Applications\Form\Attributes, Applications\Form\Base, Applications\Form\BaseFieldset, Applications\Form\CarbonCopyFieldset, Applications\Form\CommentForm, Applications\Form\ContactContainer, Applications\Form\Facts, Applications\Form\FactsFieldset, Applications\Form\Mail, Applications\Form\SettingsFieldset, Applications\Paginator\JobSelectPaginator, ArrayIterator, ArrayObject, Auth\Form\ForgotPassword, Auth\Form\Group, Auth\Form\GroupFieldset, Auth\Form\GroupUsersCollection, Auth\Form\Login, Auth\Form\Register, Auth\Form\SocialProfiles, Auth\Form\SocialProfilesFieldset, Auth\Form\UserBase, Auth\Form\UserBaseFieldset, Auth\Form\UserInfo, Auth\Form\UserInfoContainer, Auth\Form\UserInfoFieldset, Auth\Form\UserPassword, Auth\Form\UserPasswordFieldset, Auth\Form\UserProfileContainer, Auth\Form\UserStatus, Auth\Form\UserStatusContainer, Auth\Form\UserStatusFieldset, Behat\Testwork\Call\CallResults, Behat\Testwork\Output\No...ener\ChainEventListener, Behat\Testwork\Specifica...cificationArrayIterator, Behat\Testwork\Tester\Result\TestResults, CachingIterator, Core\Collection\IdentityWrapper, Core\Entity\Collection\ArrayCollection, Core\Form\BaseForm, Core\Form\ButtonsFieldset, Core\Form\CollectionContainer, Core\Form\Container, Core\Form\DefaultButtonsFieldset, Core\Form\Form, Core\Form\FormSubmitButtonsFieldset, Core\Form\ListFilterButtonsFieldset, Core\Form\LocalizationSettingsFieldset, Core\Form\MetaDataFieldset, Core\Form\PermissionsCollection, Core\Form\PermissionsFieldset, Core\Form\RatingFieldset, Core\Form\SearchForm, Core\Form\SummaryForm, Core\Form\SummaryFormButtonsFieldset, Core\Form\Tree\AddItemFieldset, Core\Form\Tree\ManagementFieldset, Core\Form\Tree\ManagementForm, Core\Form\ViewPartialProviderAbstract, Core\Form\WizardContainer, Core\Mail\MailServiceConfig, Cv\Form\CvContainer, Cv\Form\EducationFieldset, Cv\Form\EducationForm, Cv\Form\EmploymentFieldset, Cv\Form\EmploymentForm, Cv\Form\LanguageSkillFieldset, Cv\Form\LanguageSkillForm, Cv\Form\NativeLanguageFieldset, Cv\Form\NativeLanguageForm, Cv\Form\PreferredJobFieldset, Cv\Form\PreferredJobForm, Cv\Form\SearchForm, Cv\Form\SkillFieldset, Cv\Form\SkillForm, DoctrineTest\Instantiato...tAsset\ArrayObjectAsset, DoctrineTest\InstantiatorTestAsset\PharAsset, DoctrineTest\Instantiato...lizableArrayObjectAsset, DoctrineTest\Instantiato...ceptionArrayObjectAsset, DoctrineTest\Instantiato...sset\WakeUpNoticesAsset, Doctrine\Common\Collections\AbstractLazyCollection, Doctrine\Common\Collections\ArrayCollection, Doctrine\MongoDB\ArrayIterator, Doctrine\MongoDB\CommandCursor, Doctrine\MongoDB\Cursor, Doctrine\MongoDB\EagerCursor, Doctrine\MongoDB\LoggableCursor, Doctrine\MongoDB\Query\Query, Doctrine\ODM\MongoDB\Cursor, Doctrine\ODM\MongoDB\EagerCursor, Doctrine\ODM\MongoDB\PersistentCollection, Doctrine\ODM\MongoDB\Query\Query, Doctrine\ODM\MongoDB\Tools\Console\MetadataFilter, Facebook\GraphNodes\Collection, Facebook\GraphNodes\GraphAchievement, Facebook\GraphNodes\GraphAlbum, Facebook\GraphNodes\GraphApplication, Facebook\GraphNodes\GraphCoverPhoto, Facebook\GraphNodes\GraphEdge, Facebook\GraphNodes\GraphEvent, Facebook\GraphNodes\GraphGroup, Facebook\GraphNodes\GraphList, Facebook\GraphNodes\GraphLocation, Facebook\GraphNodes\GraphNode, Facebook\GraphNodes\GraphObject, Facebook\GraphNodes\GraphPage, Facebook\GraphNodes\GraphPicture, Facebook\GraphNodes\GraphSessionInfo, Facebook\GraphNodes\GraphUser, GeoJson\Feature\FeatureCollection, GeoJson\Geometry\GeometryCollection, GlobIterator, Guzzle\Common\Collection, Guzzle\Common\Exception\ExceptionCollection, Guzzle\Http\Exception\MultiTransferException, Guzzle\Http\Message\Header, Guzzle\Http\Message\Header\CacheControl, Guzzle\Http\Message\Header\HeaderCollection, Guzzle\Http\Message\Header\Link, Guzzle\Http\QueryString, Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar, Guzzle\Plugin\Cookie\CookieJar\FileCookieJar, Guzzle\Plugin\History\HistoryPlugin, Guzzle\Service\Command\AbstractCommand, Guzzle\Service\Command\ClosureCommand, Guzzle\Service\Command\Factory\CompositeFactory, Guzzle\Service\Command\OperationCommand, Guzzle\Service\Exception\CommandTransferException, Guzzle\Service\Resource\Model, Guzzle\Service\Resource\ResourceIterator, Guzzle\Tests\Service\Mock\Command\IterableCommand, Guzzle\Tests\Service\Mock\Command\MockCommand, Guzzle\Tests\Service\Mock\Command\OtherCommand, Guzzle\Tests\Service\Mock\Command\Sub\Sub, Guzzle\Tests\Service\Moc...del\MockCommandIterator, HTMLPurifier_StringHash, HttpMessage, HttpRequestPool, Imagine\Gd\Layers, Imagine\Gmagick\Layers, Imagine\Image\AbstractLayers, Imagine\Image\Metadata\MetadataBag, Imagine\Imagick\Layers, Install\Form\Installation, Issue523, Jobs\Form\AdminJobEdit, Jobs\Form\AdminSearchFormElementsFieldset, Jobs\Form\AtsMode, Jobs\Form\AtsModeFieldset, Jobs\Form\Base, Jobs\Form\BaseFieldset, Jobs\Form\CategoriesContainer, Jobs\Form\ClassificationsFieldset, Jobs\Form\ClassificationsForm, Jobs\Form\CompanyName, Jobs\Form\CompanyNameFieldset, Jobs\Form\CustomerNote, Jobs\Form\CustomerNoteFieldset, Jobs\Form\Import, Jobs\Form\ImportFieldset, Jobs\Form\Job, Jobs\Form\JobDescription, Jobs\Form\JobDescriptionBenefits, Jobs\Form\JobDescriptionDescription, Jobs\Form\JobDescriptionFieldset, Jobs\Form\JobDescriptionHtml, Jobs\Form\JobDescriptionQualifications, Jobs\Form\JobDescriptionRequirements, Jobs\Form\JobDescriptionTemplate, Jobs\Form\JobDescriptionTitle, Jobs\Form\JobboardSearch, Jobs\Form\ListFilter, Jobs\Form\ListFilterAdmin, Jobs\Form\ListFilterAdminFieldset, Jobs\Form\ListFilterBaseFieldset, Jobs\Form\ListFilterLocation, Jobs\Form\ListFilterLocationFieldset, Jobs\Form\ListFilterPersonal, Jobs\Form\ListFilterPersonalFieldset, Jobs\Form\Multipost, Jobs\Form\MultipostButtonFieldset, Jobs\Form\MultipostFieldset, Jobs\Form\Preview, Jobs\Form\PreviewFieldset, Jobs\Form\TemplateLabelBenefits, Jobs\Form\TemplateLabelQualifications, Jobs\Form\TemplateLabelRequirements, MongoCursor, MongoGridFSCursor, Organizations\Form\EmployeeFieldset, Organizations\Form\Employees, Organizations\Form\EmployeesFieldset, Organizations\Form\Organizations, Organizations\Form\OrganizationsContactFieldset, Organizations\Form\OrganizationsContactForm, Organizations\Form\Organ...ionsDescriptionFieldset, Organizations\Form\OrganizationsDescriptionForm, Organizations\Form\OrganizationsFieldset, Organizations\Form\OrganizationsNameFieldset, Organizations\Form\OrganizationsNameForm, Organizations\Form\WorkflowSettings, Organizations\Form\WorkflowSettingsFieldset, PHPUnit_Extensions_GroupTestSuite, PHPUnit_Extensions_PhptTestSuite, PHPUnit_Framework_TestSuite, PHPUnit_Framework_TestSuite_DataProvider, PHP_Token_Stream, Phar, PharData, RecursiveArrayIterator, RecursiveCachingIterator, SQLiteResult, SebastianBergmann\CodeCoverage\Node\Directory, Settings\Form\AbstractSettingsForm, Settings\Form\DisableEle...bleFormSettingsFieldset, Settings\Form\FormAbstract, Settings\Form\Settings, Settings\Form\SettingsFieldset, SimpleXMLElement, SimpleXMLIterator, SplDoublyLinkedList, SplFixedArray, SplHeap, SplMaxHeap, SplMinHeap, SplObjectStorage, SplPriorityQueue, SplQueue, SplStack, Symfony\Component\DomCrawler\Crawler, Zend\Cache\Storage\Adapter\KeyListIterator, Zend\Code\Annotation\AnnotationCollection, Zend\Code\Scanner\AnnotationScanner, Zend\ComponentInstaller\Collection, Zend\Config\Config, Zend\Config\Processor\Queue, Zend\Di\DefinitionList, Zend\Dom\Document\NodeList, Zend\Dom\NodeList, Zend\EventManager\Filter\FilterIterator, Zend\EventManager\ResponseCollection, Zend\Feed\Reader\AbstractFeed, Zend\Feed\Reader\Collection, Zend\Feed\Reader\Collection\AbstractCollection, Zend\Feed\Reader\Collection\Author, Zend\Feed\Reader\Collection\Category, Zend\Feed\Reader\Collection\Collection, Zend\Feed\Reader\FeedSet, Zend\Feed\Reader\Feed\AbstractFeed, Zend\Feed\Reader\Feed\Atom, Zend\Feed\Reader\Feed\Atom\Source, Zend\Feed\Reader\Feed\Rss, Zend\Feed\Writer\Feed, Zend\Form\Element\Collection, Zend\Form\Fieldset, Zend\Form\Form, Zend\Form\InputFilterProviderFieldset, Zend\Http\Cookies, Zend\Http\Header\Cookie, Zend\Http\Headers, Zend\I18n\Translator\TextDomain, Zend\Mail\AddressList, Zend\Mail\Headers, Zend\Mail\Storage\AbstractStorage, Zend\Mail\Storage\Folder\Maildir, Zend\Mail\Storage\Folder\Mbox, Zend\Mail\Storage\Imap, Zend\Mail\Storage\Maildir, Zend\Mail\Storage\Mbox, Zend\Mail\Storage\Pop3, Zend\Mail\Storage\Writable\Maildir, Zend\Mvc\Console\View\ViewModel, Zend\Mvc\Plugin\FlashMessenger\FlashMessenger, Zend\Navigation\AbstractContainer, Zend\Navigation\Navigation, Zend\Navigation\Page\AbstractPage, Zend\Navigation\Page\Mvc, Zend\Navigation\Page\Uri, Zend\Paginator\Paginator, Zend\Router\PriorityList, Zend\Session\AbstractContainer, Zend\Session\Container, Zend\Session\Storage\AbstractSessionArrayStorage, Zend\Session\Storage\ArrayStorage, Zend\Session\Storage\SessionArrayStorage, Zend\Session\Storage\SessionStorage, Zend\Stdlib\ArrayObject, Zend\Stdlib\ArrayStack, Zend\Stdlib\FastPriorityQueue, Zend\Stdlib\Parameters, Zend\Stdlib\PriorityList, Zend\Stdlib\PriorityQueue, Zend\Stdlib\SplPriorityQueue, Zend\Stdlib\SplQueue, Zend\Stdlib\SplStack, Zend\View\Helper\HeadLink, Zend\View\Helper\HeadMeta, Zend\View\Helper\HeadScript, Zend\View\Helper\HeadStyle, Zend\View\Helper\HeadTitle, Zend\View\Helper\InlineScript, Zend\View\Helper\Placeholder\Container, Zend\View\Helper\Placeho...ainer\AbstractContainer, Zend\View\Helper\Placeho...iner\AbstractStandalone, Zend\View\Model\ConsoleModel, Zend\View\Model\FeedModel, Zend\View\Model\JsonModel, Zend\View\Model\ViewModel, Zend\View\Resolver\AggregateResolver, Zend\View\Variables.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
214
    }
215
216
    public function addChild(NodeInterface $child)
217
    {
218
        $this->getChildren()->add($child);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Traversable as the method add() does only exist in the following implementations of said interface: Applications\Form\ApplicationsFilter, Applications\Form\Attributes, Applications\Form\Base, Applications\Form\BaseFieldset, Applications\Form\CarbonCopyFieldset, Applications\Form\CommentForm, Applications\Form\Facts, Applications\Form\FactsFieldset, Applications\Form\Mail, Applications\Form\SettingsFieldset, Auth\Form\ForgotPassword, Auth\Form\Group, Auth\Form\GroupFieldset, Auth\Form\GroupUsersCollection, Auth\Form\Login, Auth\Form\Register, Auth\Form\SocialProfiles, Auth\Form\SocialProfilesFieldset, Auth\Form\UserBase, Auth\Form\UserBaseFieldset, Auth\Form\UserInfo, Auth\Form\UserInfoFieldset, Auth\Form\UserPassword, Auth\Form\UserPasswordFieldset, Auth\Form\UserStatus, Auth\Form\UserStatusFieldset, Core\Collection\IdentityWrapper, Core\Entity\Collection\ArrayCollection, Core\Form\BaseForm, Core\Form\ButtonsFieldset, Core\Form\DefaultButtonsFieldset, Core\Form\Form, Core\Form\FormSubmitButtonsFieldset, Core\Form\ListFilterButtonsFieldset, Core\Form\LocalizationSettingsFieldset, Core\Form\MetaDataFieldset, Core\Form\PermissionsCollection, Core\Form\PermissionsFieldset, Core\Form\RatingFieldset, Core\Form\SearchForm, Core\Form\SummaryForm, Core\Form\SummaryFormButtonsFieldset, Core\Form\Tree\AddItemFieldset, Core\Form\Tree\ManagementFieldset, Core\Form\Tree\ManagementForm, Cv\Form\EducationFieldset, Cv\Form\EducationForm, Cv\Form\EmploymentFieldset, Cv\Form\EmploymentForm, Cv\Form\LanguageSkillFieldset, Cv\Form\LanguageSkillForm, Cv\Form\NativeLanguageFieldset, Cv\Form\NativeLanguageForm, Cv\Form\PreferredJobFieldset, Cv\Form\PreferredJobForm, Cv\Form\SearchForm, Cv\Form\SkillFieldset, Cv\Form\SkillForm, Doctrine\Common\Collections\AbstractLazyCollection, Doctrine\Common\Collections\ArrayCollection, Doctrine\ODM\MongoDB\PersistentCollection, Facebook\FacebookBatchRequest, Guzzle\Common\Collection, Guzzle\Common\Exception\ExceptionCollection, Guzzle\Http\Exception\MultiTransferException, Guzzle\Http\Message\Header, Guzzle\Http\Message\Header\CacheControl, Guzzle\Http\Message\Header\HeaderCollection, Guzzle\Http\Message\Header\Link, Guzzle\Http\QueryString, Guzzle\Plugin\Cookie\CookieJar\ArrayCookieJar, Guzzle\Plugin\Cookie\CookieJar\FileCookieJar, Guzzle\Plugin\History\HistoryPlugin, Guzzle\Service\Command\AbstractCommand, Guzzle\Service\Command\ClosureCommand, Guzzle\Service\Command\Factory\CompositeFactory, Guzzle\Service\Command\OperationCommand, Guzzle\Service\Exception\CommandTransferException, Guzzle\Service\Resource\Model, Guzzle\Tests\Service\Mock\Command\IterableCommand, Guzzle\Tests\Service\Mock\Command\MockCommand, Guzzle\Tests\Service\Mock\Command\OtherCommand, Guzzle\Tests\Service\Mock\Command\Sub\Sub, Imagine\Gd\Layers, Imagine\Gmagick\Layers, Imagine\Image\AbstractLayers, Imagine\Imagick\Layers, Install\Form\Installation, Jobs\Form\AdminJobEdit, Jobs\Form\AdminSearchFormElementsFieldset, Jobs\Form\AtsMode, Jobs\Form\AtsModeFieldset, Jobs\Form\Base, Jobs\Form\BaseFieldset, Jobs\Form\ClassificationsFieldset, Jobs\Form\ClassificationsForm, Jobs\Form\CompanyName, Jobs\Form\CompanyNameFieldset, Jobs\Form\CustomerNote, Jobs\Form\CustomerNoteFieldset, Jobs\Form\Import, Jobs\Form\ImportFieldset, Jobs\Form\JobDescriptionBenefits, Jobs\Form\JobDescriptionDescription, Jobs\Form\JobDescriptionFieldset, Jobs\Form\JobDescriptionHtml, Jobs\Form\JobDescriptionQualifications, Jobs\Form\JobDescriptionRequirements, Jobs\Form\JobDescriptionTitle, Jobs\Form\JobboardSearch, Jobs\Form\ListFilter, Jobs\Form\ListFilterAdmin, Jobs\Form\ListFilterAdminFieldset, Jobs\Form\ListFilterBaseFieldset, Jobs\Form\ListFilterLocation, Jobs\Form\ListFilterLocationFieldset, Jobs\Form\ListFilterPersonal, Jobs\Form\ListFilterPersonalFieldset, Jobs\Form\Multipost, Jobs\Form\MultipostButtonFieldset, Jobs\Form\MultipostFieldset, Jobs\Form\Preview, Jobs\Form\PreviewFieldset, Jobs\Form\TemplateLabelBenefits, Jobs\Form\TemplateLabelQualifications, Jobs\Form\TemplateLabelRequirements, Organizations\Form\EmployeeFieldset, Organizations\Form\Employees, Organizations\Form\EmployeesFieldset, Organizations\Form\OrganizationsContactFieldset, Organizations\Form\OrganizationsContactForm, Organizations\Form\Organ...ionsDescriptionFieldset, Organizations\Form\OrganizationsDescriptionForm, Organizations\Form\OrganizationsFieldset, Organizations\Form\OrganizationsNameFieldset, Organizations\Form\OrganizationsNameForm, Organizations\Form\WorkflowSettings, Organizations\Form\WorkflowSettingsFieldset, Settings\Form\AbstractSettingsForm, Settings\Form\DisableEle...bleFormSettingsFieldset, Settings\Form\FormAbstract, Settings\Form\Settings, Settings\Form\SettingsFieldset, Symfony\Component\DomCrawler\Crawler, Zend\Form\Element\Collection, Zend\Form\Fieldset, Zend\Form\Form, Zend\Form\InputFilterProviderFieldset, Zend\Mail\AddressList, Zend\View\Resolver\TemplateMapResolver.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
219
        $child->setParent($this);
220
221
        return $this;
222
    }
223
224
    public function removeChild(NodeInterface $child)
225
    {
226
        $this->getChildren()->removeElement($child);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Traversable as the method removeElement() does only exist in the following implementations of said interface: Core\Collection\IdentityWrapper, Core\Entity\Collection\ArrayCollection, Doctrine\Common\Collections\AbstractLazyCollection, Doctrine\Common\Collections\ArrayCollection, Doctrine\ODM\MongoDB\PersistentCollection.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
227
228
        return $this;
229
    }
230
231
    public function clearChildren()
232
    {
233
        $this->getChildren()->clear();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Traversable as the method clear() does only exist in the following implementations of said interface: Core\Collection\IdentityWrapper, Core\Entity\Collection\ArrayCollection, Doctrine\Common\Collections\AbstractLazyCollection, Doctrine\Common\Collections\ArrayCollection, Doctrine\ODM\MongoDB\PersistentCollection, Guzzle\Common\Collection, Guzzle\Http\Message\Header\HeaderCollection, Guzzle\Http\QueryString, Guzzle\Plugin\History\HistoryPlugin, Guzzle\Service\Command\AbstractCommand, Guzzle\Service\Command\ClosureCommand, Guzzle\Service\Command\OperationCommand, Guzzle\Service\Resource\Model, Guzzle\Tests\Service\Mock\Command\IterableCommand, Guzzle\Tests\Service\Mock\Command\MockCommand, Guzzle\Tests\Service\Mock\Command\OtherCommand, Guzzle\Tests\Service\Mock\Command\Sub\Sub, Imagick, ImagickPixelIterator, SolrDocument, Symfony\Component\DomCrawler\Crawler, Zend\Router\PriorityList, Zend\Session\Storage\AbstractSessionArrayStorage, Zend\Session\Storage\ArrayStorage, Zend\Session\Storage\SessionArrayStorage, Zend\Session\Storage\SessionStorage, Zend\Stdlib\PriorityList, Zend\View\Variables.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
234
235
        return $this;
236
    }
237
238
    public function setParent(NodeInterface $parent)
239
    {
240
        $this->parent = $parent;
241
242
        return $this;
243
    }
244
245
    /**
246
     *
247
     *
248
     * @return NodeInterface
249
     */
250
    public function getParent()
251
    {
252
        return $this->parent;
253
    }
254
}
255