Completed
Pull Request — 5.6 (#2830)
by Jeroen
14:14
created

Command/GoogleAnalyticsDataCollectCommand.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Kunstmaan\DashboardBundle\Command;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\ChartDataCommandHelper;
7
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\GoalCommandHelper;
8
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\MetricsCommandHelper;
9
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\UsersCommandHelper;
10
use Kunstmaan\DashboardBundle\Entity\AnalyticsConfig;
11
use Kunstmaan\DashboardBundle\Entity\AnalyticsOverview;
12
use Kunstmaan\DashboardBundle\Entity\AnalyticsSegment;
13
use Kunstmaan\DashboardBundle\Helper\Google\Analytics\ServiceHelper;
14
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Input\InputOption;
17
use Symfony\Component\Console\Output\OutputInterface;
18
19
/**
20
 * @final since 5.1
21
 * NEXT_MAJOR extend from `Command` and remove `$this->getContainer` usages
22
 */
23
class GoogleAnalyticsDataCollectCommand extends ContainerAwareCommand
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Bundle\Framework...d\ContainerAwareCommand has been deprecated with message: since Symfony 4.2, use {@see Command} instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

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

Loading history...
24
{
25
    /** @var EntityManagerInterface */
26
    private $em;
27
28
    /** @var OutputInterface */
29
    private $output;
30
31
    /** @var int */
32
    private $errors = 0;
33
34
    /** @var ServiceHelper */
35
    private $serviceHelper;
36
37
    /**
38
     * @param EntityManagerInterface|null $em
39
     * @param ServiceHelper               $serviceHelper
40
     */
41 View Code Duplication
    public function __construct(/* EntityManagerInterface */ $em = null, ServiceHelper $serviceHelper = null)
42
    {
43
        parent::__construct();
44
45
        if (!$em instanceof EntityManagerInterface) {
46
            @trigger_error(sprintf('Passing a command name as the first argument of "%s" is deprecated since version symfony 3.4 and will be removed in symfony 4.0. If the command was registered by convention, make it a service instead. ', __METHOD__), E_USER_DEPRECATED);
47
48
            $this->setName(null === $em ? 'kuma:dashboard:widget:googleanalytics:data:collect' : $em);
49
50
            return;
51
        }
52
53
        $this->em = $em;
54
        $this->serviceHelper = $serviceHelper;
55
    }
56
57
    /**
58
     * Configures the current command.
59
     */
60
    protected function configure()
61
    {
62
        $this
63
            ->setName('kuma:dashboard:widget:googleanalytics:data:collect')
64
            ->setDescription('Collect the Google Analytics dashboard widget data')
65
            ->addOption(
66
                'config',
67
                null,
68
                InputOption::VALUE_OPTIONAL,
69
                'Specify to only update one config',
70
                false
71
            )
72
            ->addOption(
73
                'segment',
74
                null,
75
                InputOption::VALUE_OPTIONAL,
76
                'Specify to only update one segment',
77
                false
78
            )
79
            ->addOption(
80
                'overview',
81
                null,
82
                InputOption::VALUE_OPTIONAL,
83
                'Specify to only update one overview',
84
                false
85
            );
86
    }
87
88
    /**
89
     * @return int|void|null
90
     */
91
    protected function execute(InputInterface $input, OutputInterface $output)
92
    {
93
        if (null === $this->em) {
94
            $this->em = $this->getContainer()->get('doctrine.orm.entity_manager');
95
        }
96
97
        if (null === $this->serviceHelper) {
98
            $this->serviceHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.service');
99
        }
100
101
        $this->output = $output;
102
103
        // check if token is set
104
        $configHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.config');
105
        if (!$configHelper->tokenIsSet()) {
106
            $this->output->writeln('You haven\'t configured a Google account yet');
107
108
            return 0;
109
        }
110
111
        // get params
112
        $configId = false;
113
        $segmentId = false;
114
        $overviewId = false;
115
116
        try {
117
            $configId = $input->getOption('config');
118
            $segmentId = $input->getOption('segment');
119
            $overviewId = $input->getOption('overview');
120
        } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
121
        }
122
123
        // get the overviews
124
        try {
125
            $overviews = [];
126
127
            if ($overviewId) {
128
                $overviews[] = $this->getSingleOverview($overviewId);
129
            } elseif ($segmentId) {
130
                $overviews = $this->getOverviewsOfSegment($segmentId);
131
            } elseif ($configId) {
132
                $overviews = $this->getOverviewsOfConfig($configId);
133
            } else {
134
                $overviews = $this->getAllOverviews();
135
            }
136
137
            // update the overviews
138
            $this->updateData($overviews);
139
            $result = '<fg=green>Google Analytics data updated with <fg=red>' . $this->errors . '</fg=red> error';
140
            $result .= $this->errors != 1 ? 's</fg=green>' : '</fg=green>';
141
            $this->output->writeln($result); // done
142
143
            return 0;
144
        } catch (\Exception $e) {
145
            $this->output->writeln($e->getMessage());
146
147
            return 1;
148
        }
149
    }
150
151
    /**
152
     * get a single overview
153
     *
154
     * @param int $overviewId
155
     *
156
     * @return AnalyticsOverview
157
     */
158
    private function getSingleOverview($overviewId)
159
    {
160
        // get specified overview
161
        $overviewRepository = $this->em->getRepository(AnalyticsOverview::class);
162
        $overview = $overviewRepository->find($overviewId);
163
164
        if (!$overview) {
165
            throw new \Exception('Unkown overview ID');
166
        }
167
168
        return $overview;
169
    }
170
171
    /**
172
     * get all overviews of a segment
173
     *
174
     * @param int $segmentId
175
     *
176
     * @return array
177
     */
178 View Code Duplication
    private function getOverviewsOfSegment($segmentId)
0 ignored issues
show
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...
179
    {
180
        // get specified segment
181
        $segmentRepository = $this->em->getRepository(AnalyticsSegment::class);
182
        $segment = $segmentRepository->find($segmentId);
183
184
        if (!$segment) {
185
            throw new \Exception('Unkown segment ID');
186
        }
187
188
        // init the segment
189
        $segmentRepository->initSegment($segment);
190
191
        // get the overviews
192
        return $segment->getOverviews();
193
    }
194
195
    /**
196
     * get all overviews of a config
197
     *
198
     * @param int $configId
199
     *
200
     * @return array
201
     */
202
    private function getOverviewsOfConfig($configId)
203
    {
204
        $configRepository = $this->em->getRepository(AnalyticsConfig::class);
205
        $segmentRepository = $this->em->getRepository(AnalyticsSegment::class);
206
        $overviewRepository = $this->em->getRepository(AnalyticsOverview::class);
207
        // get specified config
208
        $config = $configRepository->find($configId);
209
210
        if (!$config) {
211
            throw new \Exception('Unkown config ID');
212
        }
213
214
        // create default overviews for this config if none exist yet
215
        if (!\count($config->getOverviews())) {
216
            $overviewRepository->addOverviews($config);
217
        }
218
219
        // init all the segments for this config
220
        $segments = $config->getSegments();
221
        foreach ($segments as $segment) {
222
            $segmentRepository->initSegment($segment);
223
        }
224
225
        // get the overviews
226
        return $config->getOverviews();
227
    }
228
229
    /**
230
     * get all overviews
231
     *
232
     * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use object[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
233
     */
234 View Code Duplication
    private function getAllOverviews()
0 ignored issues
show
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...
235
    {
236
        $configRepository = $this->em->getRepository(AnalyticsConfig::class);
237
        $overviewRepository = $this->em->getRepository(AnalyticsOverview::class);
238
        $segmentRepository = $this->em->getRepository(AnalyticsSegment::class);
239
        $configs = $configRepository->findAll();
240
241
        foreach ($configs as $config) {
242
            // add overviews if none exist yet
243
            if (\count($config->getOverviews()) == 0) {
244
                $overviewRepository->addOverviews($config);
245
            }
246
247
            // init all the segments for this config
248
            $segments = $config->getSegments();
249
            foreach ($segments as $segment) {
250
                $segmentRepository->initSegment($segment);
251
            }
252
        }
253
254
        // get all overviews
255
        return $overviewRepository->findAll();
256
    }
257
258
    /**
259
     * update the overviews
260
     *
261
     * @param array $overviews collection of all overviews which need to be updated
262
     */
263
    public function updateData($overviews)
264
    {
265
        // helpers
266
        $queryHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.query');
267
        $configHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.config');
268
        $metrics = new MetricsCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
269
        $chartData = new ChartDataCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
270
        $goals = new GoalCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
271
        $visitors = new UsersCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
272
273
        // get data per overview
274
        foreach ($overviews as $overview) {
275
            $configHelper->init($overview->getConfig()->getId());
276
            /* @var AnalyticsOverview $overview */
277
            $this->output->writeln('Fetching data for overview "<fg=green>' . $overview->getTitle() . '</fg=green>"');
278
279
            try {
280
                // metric data
281
                $metrics->getData($overview);
282
                if ($overview->getSessions()) { // if there are any visits
283
                    // day-specific data
284
                    $chartData->getData($overview);
285
286
                    // get goals
287
                    $goals->getData($overview);
288
289
                    // visitor types
290
                    $visitors->getData($overview);
291
                } else {
292
                    // reset overview
293
                    $this->reset($overview);
294
                    $this->output->writeln("\t" . 'No visitors');
295
                }
296
                // persist entity back to DB
297
                $this->output->writeln("\t" . 'Persisting..');
298
                $this->em->persist($overview);
299
                $this->em->flush();
300
301
                $this->em->getRepository(AnalyticsConfig::class)->setUpdated($overview->getConfig()->getId());
302
            } catch (\Google_ServiceException $e) {
303
                $error = explode(')', $e->getMessage());
304
                $error = $error[1];
305
                $this->output->writeln("\t" . '<fg=red>Invalid segment: </fg=red>' . $error);
306
                ++$this->errors;
307
            }
308
        }
309
    }
310
311
    /**
312
     * Reset the data for the overview
313
     *
314
     * @param AnalyticsOverview $overview The overview
315
     */
316
    private function reset(AnalyticsOverview $overview)
317
    {
318
        // reset overview
319
        $overview->setNewUsers(0);
320
        $overview->setReturningUsers(0);
321
    }
322
}
323