Completed
Push — master ( 3c857d...bdbb05 )
by Gaetano
15:11
created

MailExecutor   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 134
Duplicated Lines 24.63 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 5
dl 33
loc 134
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A execute() 16 16 3
F send() 0 50 13
A resolveReferencesRecursively() 11 11 3
A resolveReferencesInText() 6 18 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use Kaliop\eZMigrationBundle\API\Value\MigrationStep;
6
use Kaliop\eZMigrationBundle\API\ReferenceResolverInterface;
7
use Kaliop\eZMigrationBundle\Core\ReferenceResolver\PrefixBasedResolverInterface;
8
use Swift_Message;
9
use Swift_Attachment;
10
11
class MailExecutor extends AbstractExecutor
12
{
13
    protected $supportedStepTypes = array('mail');
14
    protected $supportedActions = array('send');
15
16
    protected $mailService;
17
    /** @var ReferenceResolverInterface $referenceResolver */
18
    protected $referenceResolver;
19
20
    public function __construct($mailService, PrefixBasedResolverInterface $referenceResolver)
21
    {
22
        $this->mailService = $mailService;
23
        $this->referenceResolver = $referenceResolver;
24
    }
25
26
    /**
27
     * @param MigrationStep $step
28
     * @return mixed
29
     * @throws \Exception
30
     */
31 View Code Duplication
    public function execute(MigrationStep $step)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
32
    {
33
        parent::execute($step);
34
35
        if (!isset($step->dsl['mode'])) {
36
            throw new \Exception("Invalid step definition: missing 'mode'");
37
        }
38
39
        $action = $step->dsl['mode'];
40
41
        if (!in_array($action, $this->supportedActions)) {
42
            throw new \Exception("Invalid step definition: value '$action' is not allowed for 'mode'");
43
        }
44
45
        return $this->$action($step->dsl, $step->context);
46
    }
47
48
    /**
49
     * @param array $dsl
50
     * @param array $context
51
     * @return true
52
     * @throws \Exception
53
     */
54
    protected function send($dsl, $context)
0 ignored issues
show
Unused Code introduced by
The parameter $context 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...
55
    {
56
57
        $message = Swift_Message::newInstance();
58
59
        if (isset($dsl['from'])) {
60
            $message->setFrom($this->resolveReferencesRecursively($dsl['from']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
61
        }
62
        if (isset($dsl['to'])) {
63
            $message->setTo($this->resolveReferencesRecursively($dsl['to']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
64
        }
65
        if (isset($dsl['cc'])) {
66
            $message->setCc($this->resolveReferencesRecursively($dsl['cc']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
67
        }
68
        if (isset($dsl['bcc'])) {
69
            $message->setBcc($this->resolveReferencesRecursively($dsl['bcc']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
70
        }
71
        if (isset($dsl['subject'])) {
72
            $message->setSubject($this->resolveReferencesInText($dsl['subject']));
73
        }
74
        if (isset($dsl['body'])) {
75
            $message->setBody($this->resolveReferencesInText($dsl['body']));
76
        }
77
        if (isset($dsl['attach'])) { /// @todo
78
            $message->attach(Swift_Attachment::fromPath($this->resolveReferencesRecursively($dsl['attach'])));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
79
        }
80
81
        if (isset($dsl['priority'])) {
82
            $message->setPriority($this->resolveReferencesRecursively($dsl['priority']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
83
        }
84
        if (isset($dsl['read_receipt_to'])) {
85
            $message->setReadReceiptTo($this->resolveReferencesRecursively($dsl['read_receipt_to']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
86
        }
87
        if (isset($dsl['return_path'])) {
88
            $message->setReturnPath($this->resolveReferencesRecursively($dsl['return_path']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
89
        }
90
        if (isset($dsl['reply_to'])) {
91
            $message->setReplyTo($this->resolveReferencesRecursively($dsl['reply_to']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
92
        }
93
        if (isset($dsl['sender'])) {
94
            $message->setSender($this->resolveReferencesRecursively($dsl['sender']));
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
95
        }
96
97
        $this->mailService->send($message);
98
99
        // q: shall we set any reference?
100
101
        // q: what to return?
102
        return true;
103
    }
104
105
    /**
106
     * @deprecated should be moved into the reference resolver classes
107
     */
108 View Code Duplication
    protected function resolveReferencesRecursively($match)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109
    {
110
        if (is_array($match)) {
111
            foreach ($match as $condition => $values) {
112
                $match[$condition] = $this->resolveReferencesRecursively($values);
0 ignored issues
show
Deprecated Code introduced by
The method Kaliop\eZMigrationBundle...ReferencesRecursively() has been deprecated with message: should be moved into the reference resolver classes

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
113
            }
114
            return $match;
115
        } else {
116
            return $this->referenceResolver->resolveReference($match);
117
        }
118
    }
119
120
    /**
121
     * Replaces any references inside a string
122
     *
123
     * @param string
124
     * @return string
125
     */
126
    protected function resolveReferencesInText($text)
127
    {
128
        // we need to alter the regexp we get from the resolver, as it will be used to match parts of text, not the whole string
129
        $regexp = substr($this->referenceResolver->getRegexp(), 1, -1);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Kaliop\eZMigrationBundle...erenceResolverInterface as the method getRegexp() does only exist in the following implementations of said interface: Kaliop\eZMigrationBundle...solver\AbstractResolver, Kaliop\eZMigrationBundle...ver\ChainPrefixResolver, Kaliop\eZMigrationBundle...ver\ChainRegexpResolver, Kaliop\eZMigrationBundle...esolver\ContentResolver, Kaliop\eZMigrationBundle...CustomReferenceResolver, Kaliop\eZMigrationBundle...solver\LocationResolver, Kaliop\eZMigrationBundle...ver\PrefixBasedResolver, Kaliop\eZMigrationBundle...nceResolver\TagResolver.

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...
130
        // NB: here we assume that all regexp resolvers give us a regexp with a very specific format...
131
        $regexp = '/\[' . preg_replace(array('/^\^/'), array('', ''), $regexp) . '[^]]+\]/';
132
133
        $count = preg_match_all($regexp, $text, $matches);
134
        // $matches[0][] will have the matched full string eg.: [reference:example_reference]
135 View Code Duplication
        if ($count) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
136
            foreach ($matches[0] as $referenceIdentifier) {
137
                $reference = $this->referenceResolver->getReferenceValue(substr($referenceIdentifier, 1, -1));
138
                $text = str_replace($referenceIdentifier, $reference, $text);
139
            }
140
        }
141
142
        return $text;
143
    }
144
}
145