Application::__async_make()   C
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 39
rs 6.7272
cc 7
eloc 26
nc 6
nop 1
1
<?php
2
3
namespace samsoncms\newsletter;
4
5
use samson\activerecord\email_distribution;
6
use samson\activerecord\email_letter;
7
use samson\activerecord\email_template;
8
use samson\core\SamsonLocale;
9
10
class Application extends \samsoncms\Application
11
{
12
    /** @var string Module identifier */
13
    protected $id = 'newsletter';
14
15
    /** @var string Entity class name */
16
    protected $entity = '\samson\activerecord\email_distribution';
17
18
    /** Application name */
19
    public $name = 'Newsletter';
20
21
    /** Application description */
22
    public $description = 'Newsletter distribution management';
23
24
    /** @var string $icon Icon class */
25
    public $icon = 'envelope';
26
27
    public $hide = false;
28
29
    /**
30
     * Prepare DB for application settings
31
     * @return mixed
32
     */
33
    public function prepare()
34
    {
35
        db()->execute(
36
            "
37
                CREATE TABLE IF NOT EXISTS `email_distribution` (
38
                  `distribution_id` int(11) NOT NULL AUTO_INCREMENT,
39
                  `template_id` int(11) NOT NULL,
40
                  `status` int(11) DEFAULT '0',
41
                  `recipient_count` int(11) DEFAULT '0',
42
                  `bounce_count` int(11) DEFAULT '0',
43
                  `open_count` int(11) DEFAULT '0',
44
                  `click_count` int(11) DEFAULT '0',
45
                  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
46
                  `finished` datetime NOT NULL,
47
                  `active` int(11) NOT NULL DEFAULT '0',
48
                  PRIMARY KEY (`distribution_id`)
49
                ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
50
            "
51
        );
52
53
        db()->execute(
54
            "
55
                CREATE TABLE IF NOT EXISTS `email_letter` (
56
                  `letter_id` int(11) NOT NULL AUTO_INCREMENT,
57
                  `distribution_id` int(11) NOT NULL,
58
                  `template_id` int(11) NOT NULL,
59
                  `recipient` varchar(50) NOT NULL,
60
                  `status` int(11) DEFAULT '0',
61
                  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
62
                  PRIMARY KEY (`letter_id`)
63
                ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
64
            "
65
        );
66
67
        db()->execute(
68
            "
69
                CREATE TABLE IF NOT EXISTS `email_template` (
70
                  `template_id` int(11) NOT NULL AUTO_INCREMENT,
71
                  `content` text NOT NULL,
72
                  `locale` varchar(5) NOT NULL DEFAULT 'en',
73
                  `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
74
                  PRIMARY KEY (`template_id`)
75
                ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
76
            "
77
        );
78
79
        return parent::prepare();
80
    }
81
82
    /**
83
     * Universal controller action.
84
     * Entity collection rendering
85
     */
86
    public function __template()
87
    {
88
        $description = t($this->description, true);
89
        $name = t($this->description, true);
90
        $letter = $this->createLetter('HEADER', 'MESSAGE');
91
92
        // Prepare view
93
        $this->title($description)
94
            ->view('form')
95
            ->set('name', $name)
96
            ->set('icon', $this->icon)
97
            ->set('letter', $letter)
98
            ->set('description', $description)
99
        ;
100
    }
101
102
    /**
103
     * Save number of email opens
104
     * @param int $distribution_id Distribution identifier
105
     */
106
    public function __openaction($distribution_id)
107
    {
108
        /** @var email_distribution $distribution */
109
        $distribution = null;
110
        if ($this->query->entity('email_distribution')->where('distribution_id', $distribution_id)->first($distribution)) {
111
            $distribution->open_count ++;
0 ignored issues
show
Bug introduced by
Accessing open_count on the interface samsonframework\orm\RecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
112
            $distribution->save();
113
        }
114
    }
115
116
    /**
117
     * Save number of email clicks
118
     * @param int $distribution_id Distribution identifier
119
     * @param string $params
120
     */
121
    public function __clickaction($distribution_id, $params = '')
122
    {
123
        /** @var email_distribution $distribution */
124
        $distribution = null;
125
        if ($this->query->entity('email_distribution')->where('distribution_id', $distribution_id)->first($distribution)) {
126
            $distribution->click_count ++;
0 ignored issues
show
Bug introduced by
Accessing click_count on the interface samsonframework\orm\RecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
127
            $distribution->save();
128
129
            $params = explode('-', $params);
130
            $url = 'http://'.$_SERVER['HTTP_HOST'].'/';
131
            if (sizeof($params)) {
132
                foreach ($params as $param) {
133
                    $url .= $param.'/';
134
                }
135
            }
136
137
            header('Location: '.$url);die;
0 ignored issues
show
Coding Style introduced by
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
138
        }
139
    }
140
141
    /**
142
     * Show template content
143
     * @param int $id Template identifier
144
     * @return array
145
     */
146
    public function __async_templates($id)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_templates" is not in camel caps format
Loading history...
147
    {
148
        /** @var $this->entity $outfit */
0 ignored issues
show
Documentation introduced by
The doc-type $this->entity could not be parsed: Unknown type name "$this-" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
149
        $template = null;
150
        $response = array('status' => 0, 'popup' => '');
151
        if ($this->query->entity('email_template')->where('template_id', $id)->first($template)) {
152
            $response['popup'] = $this->view('template/popup')->content($template->content)->output();
0 ignored issues
show
Bug introduced by
Accessing content on the interface samsonframework\orm\RecordInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Documentation Bug introduced by
The method content does not exist on object<samsoncms\newsletter\Application>? 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...
153
            $response['status'] = 1;
154
        }
155
156
        return $response;
157
    }
158
159
    /**
160
     * Create template content
161
     * @param string $header Email Header
162
     * @param string $message Email text
163
     * @return string
164
     */
165
    public function createLetter($header, $message)
166
    {
167
        return '<h1>'.$header.'</h1><br><div>'.$message.'</div>';
168
    }
169
170
    /**
171
     * @param int $preview Flag - send letters or no
172
     * @return array
173
     */
174
    public function __async_make($preview = 0)
0 ignored issues
show
Coding Style introduced by
Method name "Application::__async_make" is not in camel caps format
Loading history...
175
    {
176
        $recipients = explode(',', $_POST['recipients']);
177
178
        $letters = array();
179
        foreach (SamsonLocale::$locales as $locale) {
180
            if (isset($_POST['header-'.$locale]) && isset($_POST['message-'.$locale])) {
181
                $letters[$locale] = $this->createLetter($_POST['header-'.$locale], $_POST['message-'.$locale]);
182
            }
183
        }
184
185
        if (!$preview) {
186
            $templates = array();
187
188
            foreach ($letters as $locale => $letter) {
189
                $template = new email_template();
190
                $template->content = $letter;
191
                $template->locale = $locale;
192
                $template->save();
193
                $templates[$locale] = $template;
194
            }
195
196
            $distribution = new email_distribution();
197
            $distribution->template_id = $templates[SamsonLocale::$defaultLocale]->template_id;
198
            $distribution->recipient_count = sizeof($recipients);
199
            $distribution->active = 1;
200
            $distribution->save();
201
            // Send emails to all users from POST array
202
            foreach ($recipients as $recipient) {
203
                $emailLetter = new email_letter();
204
                $emailLetter->distribution_id = $distribution->distribution_id;
205
                $emailLetter->recipient = trim($recipient);
206
                $emailLetter->template_id = $templates[SamsonLocale::$defaultLocale]->template_id;
207
                $emailLetter->save();
208
            }
209
        }
210
211
        return array('status' => 1, 'preview' => $letters[SamsonLocale::$defaultLocale]);
212
    }
213
214
    /**
215
     * Send manual newsletters
216
     */
217
    public function __manual()
218
    {
219
        foreach ($this->query->entity('email_letter')->where('status', 0)->exec() as $letter) {
0 ignored issues
show
Bug introduced by
The expression $this->query->entity('em...re('status', 0)->exec() of type boolean|array<integer,ob...k\orm\RecordInterface>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
220
            $template = $this->query->entity('email_template')->where('template_id', $letter->template_id)->first();
221
            $message = $template->content;
222
            $img = '<img width="1" height="1" src="'.url()->build('newsletter/openaction/'.$letter->distribution_id).'">';
223
            $message .= $img;
224
            $message = str_replace('clickaction/', 'clickaction/'.$letter->distribution_id.'/', $message);
225
            $this->sendEmail($message, $letter->recipient);
226
            $letter->status = 1;
227
            $letter->save();
228
        }
229
    }
230
231
    /**
232
     * @param string $letter Letter html content
233
     * @param string $recipient email recipient
234
     * @param string $from Sender email
235
     * @param string $subject Email subject
236
     * @param string $user Sender name
237
     */
238
    public function sendEmail($letter, $recipient = '', $from = '', $subject = '', $user = '')
239
    {
240
        mail_send($recipient, $from, $letter, $subject, $user);
241
    }
242
}
243