Completed
Push — master ( 6d6774...64f3ed )
by Jeroen
11:23 queued 05:13
created

Command/GoogleAnalyticsDataCollectCommand.php (3 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 Kunstmaan\DashboardBundle\Command\Helper\Analytics\ChartDataCommandHelper;
6
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\GoalCommandHelper;
7
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\MetricsCommandHelper;
8
use Kunstmaan\DashboardBundle\Command\Helper\Analytics\UsersCommandHelper;
9
use Kunstmaan\DashboardBundle\Entity\AnalyticsOverview;
10
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Input\InputOption;
13
use Symfony\Component\Console\Output\OutputInterface;
14
use Doctrine\ORM\EntityManagerInterface;
15
use Kunstmaan\DashboardBundle\Helper\Google\Analytics\ServiceHelper;
16
17
/**
18
 * @final since 5.1
19
 * NEXT_MAJOR extend from `Command` and remove `$this->getContainer` usages
20
 */
21
class GoogleAnalyticsDataCollectCommand extends ContainerAwareCommand
22
{
23
    /** @var EntityManagerInterface */
24
    private $em;
25
26
    /** @var OutputInterface */
27
    private $output;
28
29
    /** @var int */
30
    private $errors = 0;
31
32
    /** @var ServiceHelper */
33
    private $serviceHelper;
34
35
    /**
36
     * @param EntityManagerInterface|null $em
37
     * @param ServiceHelper               $serviceHelper
38
     */
39 View Code Duplication
    public function __construct(/* EntityManagerInterface */ $em = null, ServiceHelper $serviceHelper = null)
40
    {
41
        parent::__construct();
42
43
        if (!$em instanceof EntityManagerInterface) {
44
            @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);
45
46
            $this->setName(null === $em ? 'kuma:dashboard:widget:googleanalytics:data:collect' : $em);
47
48
            return;
49
        }
50
51
        $this->em = $em;
52
        $this->serviceHelper = $serviceHelper;
53
    }
54
55
    /**
56
     * Configures the current command.
57
     */
58
    protected function configure()
59
    {
60
        $this
61
            ->setName('kuma:dashboard:widget:googleanalytics:data:collect')
62
            ->setDescription('Collect the Google Analytics dashboard widget data')
63
            ->addOption(
64
                'config',
65
                null,
66
                InputOption::VALUE_OPTIONAL,
67
                'Specify to only update one config',
68
                false
69
            )
70
            ->addOption(
71
                'segment',
72
                null,
73
                InputOption::VALUE_OPTIONAL,
74
                'Specify to only update one segment',
75
                false
76
            )
77
            ->addOption(
78
                'overview',
79
                null,
80
                InputOption::VALUE_OPTIONAL,
81
                'Specify to only update one overview',
82
                false
83
            );
84
    }
85
86
    /**
87
     * @param InputInterface  $input
88
     * @param OutputInterface $output
89
     *
90
     * @return int|null|void
91
     */
92
    protected function execute(InputInterface $input, OutputInterface $output)
93
    {
94
        if (null === $this->em) {
95
            $this->em = $this->getContainer()->get('doctrine.orm.entity_manager');
96
        }
97
98
        if (null === $this->serviceHelper) {
99
            $this->serviceHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.service');
100
        }
101
102
        $this->output = $output;
103
104
        // check if token is set
105
        $configHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.config');
106
        if (!$configHelper->tokenIsSet()) {
107
            $this->output->writeln('You haven\'t configured a Google account yet');
108
109
            return 0;
110
        }
111
112
        // get params
113
        $configId = false;
114
        $segmentId = false;
115
        $overviewId = false;
116
117
        try {
118
            $configId = $input->getOption('config');
119
            $segmentId = $input->getOption('segment');
120
            $overviewId = $input->getOption('overview');
121
        } catch (\Exception $e) {
122
        }
123
124
        // get the overviews
125
        try {
126
            $overviews = [];
127
128
            if ($overviewId) {
129
                $overviews[] = $this->getSingleOverview($overviewId);
130
            } elseif ($segmentId) {
131
                $overviews = $this->getOverviewsOfSegment($segmentId);
132
            } elseif ($configId) {
133
                $overviews = $this->getOverviewsOfConfig($configId);
134
            } else {
135
                $overviews = $this->getAllOverviews();
136
            }
137
138
            // update the overviews
139
            $this->updateData($overviews);
140
            $result = '<fg=green>Google Analytics data updated with <fg=red>'.$this->errors.'</fg=red> error';
141
            $result .= $this->errors != 1 ? 's</fg=green>' : '</fg=green>';
142
            $this->output->writeln($result); // done
143
144
            return 0;
145
        } catch (\Exception $e) {
146
            $this->output->writeln($e->getMessage());
147
148
            return 1;
149
        }
150
    }
151
152
    /**
153
     * get a single overview
154
     *
155
     * @param int $overviewId
156
     *
157
     * @return AnalyticsOverview
158
     */
159
    private function getSingleOverview($overviewId)
160
    {
161
        // get specified overview
162
        $overviewRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsOverview');
163
        $overview = $overviewRepository->find($overviewId);
164
165
        if (!$overview) {
166
            throw new \Exception('Unkown overview ID');
167
        }
168
169
        return $overview;
170
    }
171
172
    /**
173
     * get all overviews of a segment
174
     *
175
     * @param int $segmentId
176
     *
177
     * @return array
178
     */
179 View Code Duplication
    private function getOverviewsOfSegment($segmentId)
180
    {
181
        // get specified segment
182
        $segmentRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsSegment');
183
        $segment = $segmentRepository->find($segmentId);
184
185
        if (!$segment) {
186
            throw new \Exception('Unkown segment ID');
187
        }
188
189
        // init the segment
190
        $segmentRepository->initSegment($segment);
191
192
        // get the overviews
193
        return $segment->getOverviews();
194
    }
195
196
    /**
197
     * get all overviews of a config
198
     *
199
     * @param int $configId
200
     *
201
     * @return array
202
     */
203
    private function getOverviewsOfConfig($configId)
204
    {
205
        $configRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsConfig');
206
        $segmentRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsSegment');
207
        $overviewRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsOverview');
208
        // get specified config
209
        $config = $configRepository->find($configId);
210
211
        if (!$config) {
212
            throw new \Exception('Unkown config ID');
213
        }
214
215
        // create default overviews for this config if none exist yet
216
        if (!\count($config->getOverviews())) {
217
            $overviewRepository->addOverviews($config);
218
        }
219
220
        // init all the segments for this config
221
        $segments = $config->getSegments();
222
        foreach ($segments as $segment) {
223
            $segmentRepository->initSegment($segment);
224
        }
225
226
        // get the overviews
227
        return $config->getOverviews();
228
    }
229
230
    /**
231
     * get all overviews
232
     *
233
     * @return array
234
     */
235 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...
236
    {
237
        $configRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsConfig');
238
        $overviewRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsOverview');
239
        $segmentRepository = $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsSegment');
240
        $configs = $configRepository->findAll();
241
242
        foreach ($configs as $config) {
243
            // add overviews if none exist yet
244
            if (\count($config->getOverviews()) == 0) {
245
                $overviewRepository->addOverviews($config);
246
            }
247
248
            // init all the segments for this config
249
            $segments = $config->getSegments();
250
            foreach ($segments as $segment) {
251
                $segmentRepository->initSegment($segment);
252
            }
253
        }
254
255
        // get all overviews
256
        return $overviewRepository->findAll();
257
    }
258
259
    /**
260
     * update the overviews
261
     *
262
     * @param array $overviews collection of all overviews which need to be updated
263
     */
264
    public function updateData($overviews)
265
    {
266
        // helpers
267
        $queryHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.query');
268
        $configHelper = $this->getContainer()->get('kunstmaan_dashboard.helper.google.analytics.config');
269
        $metrics = new MetricsCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
270
        $chartData = new ChartDataCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
271
        $goals = new GoalCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
272
        $visitors = new UsersCommandHelper($configHelper, $queryHelper, $this->output, $this->em);
273
274
        // get data per overview
275
        foreach ($overviews as $overview) {
276
            $configHelper->init($overview->getConfig()->getId());
277
            /* @var AnalyticsOverview $overview */
278
            $this->output->writeln('Fetching data for overview "<fg=green>' . $overview->getTitle() . '</fg=green>"');
279
280
            try {
281
                // metric data
282
                $metrics->getData($overview);
283
                if ($overview->getSessions()) { // if there are any visits
284
                    // day-specific data
285
                    $chartData->getData($overview);
286
287
                    // get goals
288
                    $goals->getData($overview);
289
290
                    // visitor types
291
                    $visitors->getData($overview);
292
                } else {
293
                    // reset overview
294
                    $this->reset($overview);
295
                    $this->output->writeln("\t" . 'No visitors');
296
                }
297
                // persist entity back to DB
298
                $this->output->writeln("\t" . 'Persisting..');
299
                $this->em->persist($overview);
300
                $this->em->flush();
301
302
                $this->em->getRepository('KunstmaanDashboardBundle:AnalyticsConfig')->setUpdated($overview->getConfig()->getId());
0 ignored issues
show
The method getId cannot be called on $overview->getConfig() (of type integer).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method setUpdated() does only exist in the following implementations of said interface: Kunstmaan\DashboardBundl...alyticsConfigRepository.

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...
303
            } catch (\Google_ServiceException $e) {
304
                $error = explode(')', $e->getMessage());
305
                $error = $error[1];
306
                $this->output->writeln("\t" . '<fg=red>Invalid segment: </fg=red>' .$error);
307
                ++$this->errors;
308
            }
309
        }
310
    }
311
312
    /**
313
     * Reset the data for the overview
314
     *
315
     * @param AnalyticsOverview $overview The overview
316
     */
317
    private function reset(AnalyticsOverview $overview)
318
    {
319
        // reset overview
320
        $overview->setNewUsers(0);
321
        $overview->setReturningUsers(0);
322
    }
323
}
324