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

Command/GoogleAnalyticsDataCollectCommand.php (1 issue)

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()
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
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