diff --git a/SOLUTION.md b/SOLUTION.md index defe675..25cfd6d 100755 --- a/SOLUTION.md +++ b/SOLUTION.md @@ -3,11 +3,26 @@ SOLUTION Estimation ---------- -Estimated: n hours +Estimated: 3 hours -Spent: x hours +Spent: 3,5 hours + - 2 hours (thinking and redesigned the code) + - 45 min setup the environment + - 45 min coding Solution -------- -Comments on your solution +This task can be done with multiples options. One of these options I just wrote it with code. I use Laravel collection package, which helped me to easily +get array data from DB to multidimensional array (collection). + +Other options: + - The other option how can be this task done is to write raw SQL sentence and get all data with mysql. + - If I will know a little bit more Symfony ORM package, this can be also done with ORM command and you can get data out from ORM and then display in console: + +Other good solution is to display more tables if user doesn't type in year data. Tables can be separate with new line and if have in DB 10 years it will display 10 tables. +But with this solution you need to be careful, because if you get a lot of years and data in you databases it can too much loaded a server. + +This example can be upgraded in the future with nice console message if user doesn't type a year of a report and suggested a option to type a year without to return error exceptions. + +Code can be also separated into function if you need it to reuse it somewhere else. \ No newline at end of file diff --git a/composer.json b/composer.json index c6e32bd..454feb5 100755 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "symfony/dependency-injection": "^3.2", "symfony/config": "^3.2", "symfony/yaml": "^3.2", - "doctrine/dbal": "^2.5" + "doctrine/dbal": "^2.5", + "tightenco/collect": "v5.6.27" }, "license": "proprietary", "authors": [ diff --git a/composer.lock b/composer.lock index a637872..fe8a28d 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "eb07b9698db13dac12f90dc9cd3489af", + "content-hash": "6f1e0276bc4a392ab6add294ec98e3ff", "packages": [ { "name": "doctrine/annotations", @@ -920,27 +920,28 @@ "time": "2016-11-14T01:06:16+00:00" }, { - "name": "symfony/yaml", + "name": "symfony/var-dumper", "version": "v3.2.2", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "50eadbd7926e31842893c957eca362b21592a97d" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "b54b23f9a19b465e76fdaac0f6732410467c83b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/50eadbd7926e31842893c957eca362b21592a97d", - "reference": "50eadbd7926e31842893c957eca362b21592a97d", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b54b23f9a19b465e76fdaac0f6732410467c83b2", + "reference": "b54b23f9a19b465e76fdaac0f6732410467c83b2", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/console": "~2.8|~3.0" + "twig/twig": "~1.20|~2.0" }, "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "ext-symfony_debug": "" }, "type": "library", "extra": { @@ -949,8 +950,11 @@ } }, "autoload": { + "files": [ + "Resources/functions/dump.php" + ], "psr-4": { - "Symfony\\Component\\Yaml\\": "" + "Symfony\\Component\\VarDumper\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -962,43 +966,44 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Yaml Component", + "description": "Symfony mechanism for exploring and dumping PHP variables", "homepage": "https://symfony.com", - "time": "2017-01-03T13:51:32+00:00" - } - ], - "packages-dev": [ + "keywords": [ + "debug", + "dump" + ], + "time": "2017-01-03T08:53:57+00:00" + }, { - "name": "symfony/var-dumper", + "name": "symfony/yaml", "version": "v3.2.2", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "b54b23f9a19b465e76fdaac0f6732410467c83b2" + "url": "https://github.com/symfony/yaml.git", + "reference": "50eadbd7926e31842893c957eca362b21592a97d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b54b23f9a19b465e76fdaac0f6732410467c83b2", - "reference": "b54b23f9a19b465e76fdaac0f6732410467c83b2", + "url": "https://api.github.com/repos/symfony/yaml/zipball/50eadbd7926e31842893c957eca362b21592a97d", + "reference": "50eadbd7926e31842893c957eca362b21592a97d", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=5.5.9" }, "require-dev": { - "twig/twig": "~1.20|~2.0" + "symfony/console": "~2.8|~3.0" }, "suggest": { - "ext-symfony_debug": "" + "symfony/console": "For validating YAML files using the lint command" }, "type": "library", "extra": { @@ -1007,11 +1012,8 @@ } }, "autoload": { - "files": [ - "Resources/functions/dump.php" - ], "psr-4": { - "Symfony\\Component\\VarDumper\\": "" + "Symfony\\Component\\Yaml\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1023,23 +1025,70 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony mechanism for exploring and dumping PHP variables", + "description": "Symfony Yaml Component", "homepage": "https://symfony.com", + "time": "2017-01-03T13:51:32+00:00" + }, + { + "name": "tightenco/collect", + "version": "v5.6.27", + "source": { + "type": "git", + "url": "https://github.com/tightenco/collect.git", + "reference": "f80bdbf7e51461467c0103811ca9df2ec0a561d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tightenco/collect/zipball/f80bdbf7e51461467c0103811ca9df2ec0a561d5", + "reference": "f80bdbf7e51461467c0103811ca9df2ec0a561d5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/var-dumper": ">=3.1.10" + }, + "require-dev": { + "mockery/mockery": "~1.0", + "nesbot/carbon": "~1.20", + "phpunit/phpunit": "~7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Collect/Support/helpers.php", + "src/Collect/Support/alias.php" + ], + "psr-4": { + "Tightenco\\Collect\\": "src/Collect" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "Collect - Illuminate Collections as a separate package.", "keywords": [ - "debug", - "dump" + "collection", + "laravel" ], - "time": "2017-01-03T08:53:57+00:00" + "time": "2018-07-11T13:31:08+00:00" } ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], diff --git a/src/Command/ReportYearlyCommand.php b/src/Command/ReportYearlyCommand.php index 97f026f..1929453 100755 --- a/src/Command/ReportYearlyCommand.php +++ b/src/Command/ReportYearlyCommand.php @@ -6,6 +6,8 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Tightenco\Collect\Support\Collection; +use Symfony\Component\Console\Input\InputArgument; class ReportYearlyCommand extends ContainerAwareCommand { @@ -13,6 +15,7 @@ protected function configure() { $this ->setName('report:profiles:yearly') + ->addArgument('year', InputArgument::REQUIRED, 'For which year do you need a report?') ->setDescription('Page views report') ; } @@ -23,10 +26,59 @@ protected function execute(InputInterface $input, OutputInterface $output) $io = new SymfonyStyle($input,$output); $db = $this->getContainer()->get('database_connection'); - $profiles = $db->query('SELECT profile_name FROM profiles')->fetchAll(); + if($input->getArgument('year')){ + $yearOfDisplay = $input->getArgument('year'); + } - // Show data in a table - headers, data - $io->table(['Profile'], $profiles); + $profiles = collect($db->query('SELECT profile_name, date, views FROM profiles as p LEFT JOIN views as v ON p.profile_id=v.profile_id WHERE date LIKE "'.$yearOfDisplay.'-%" ORDER BY p.profile_name, v.date')->fetchAll()); + + // Group by profiles and order by alphabetic order + $export = $profiles->groupBy('profile_name')->sortBy('profile_name'); + + // SUM for each user theirs data + $export = $export->transform(function($personData){ + + return $personData->groupBy(function($month){ + + return date('M', strtotime($month['date'])); + + })->transform(function($monthValue){ + + return number_format($monthValue->sum('views')); + }); + }); + + // Display no data found. + if(sizeof($export->toArray()) == 0){ + return $io->table( + ['Profiles - '.$yearOfDisplay], + [ + ['n/a'] + ] + ); + } + + // Design array for Symfony console display + // Header with name of profiles and months + $header = $profiles->sortBy('date')->groupBy(function($val) { + + return date('M', strtotime($val['date'])); + + })->keys()->toArray(); + array_unshift($header, 'Profiles - '.$yearOfDisplay); + + + // Add profile name in the same row as totals + $data = []; + foreach($export->toArray() as $name => $monthData){ + $data[$name] = $monthData; + array_unshift($data[$name], $name); + } + + return $io->table( + $header, + $data + ); } } diff --git a/src/Tests/YearlyReport.feature b/src/Tests/YearlyReport.feature index e69de29..21399a9 100755 --- a/src/Tests/YearlyReport.feature +++ b/src/Tests/YearlyReport.feature @@ -0,0 +1,4 @@ +My weakness are tests, because I haven't need to use it on small project, but on big project where I have been worked on we didn't use test. So on this project I will need to improve myself. + +First you need set year for which you would like to get data. Then you need to check if you get any data. When console display the table you need to check id if return success message or exceptions. + Sometimes you can also checked type of given data.