├── .gitignore ├── Adapter ├── Geolocator │ ├── GeolocatorAdapter.php │ └── GeolocatorAdapterInterface.php └── Storage │ ├── StorageAdapter.php │ └── StorageAdapterInterface.php ├── Builder └── FileStatsBuilder.php ├── Command ├── AbstractCommand.php ├── StatsConverterCommand.php └── ViewcounterCleanupCommand.php ├── Compute └── StatsComputer.php ├── Counter ├── AbstractViewCounter.php └── ViewCounter.php ├── DependencyInjection ├── Compiler │ └── ViewcounterPass.php ├── Configuration.php └── TchoulomViewCounterExtension.php ├── Document └── Stats │ └── MongoDB │ ├── AuditTrait.php │ ├── City.php │ ├── Continent.php │ ├── Country.php │ ├── Day.php │ ├── Hour.php │ ├── Minute.php │ ├── Month.php │ ├── NumberTrait.php │ ├── Page.php │ ├── PageContinent.php │ ├── PageCountry.php │ ├── Region.php │ ├── Second.php │ ├── ViewTrait.php │ ├── Week.php │ └── Year.php ├── ETL └── StatsConverter.php ├── Entity ├── ViewCounter.php └── ViewCounterInterface.php ├── Exception ├── ExceptionInterface.php ├── IOException.php ├── IOExceptionInterface.php └── RuntimeException.php ├── Finder └── FileStatsFinder.php ├── Geolocation ├── City.php ├── Country.php └── Region.php ├── LICENSE ├── Manager ├── CounterManager.php └── StatsManager.php ├── Model ├── StatisticsNodeConfig.php ├── ViewCountable.php ├── ViewcounterConfig.php └── ViewcounterNodeConfig.php ├── README.md ├── Repository ├── AbstractRepository.php ├── CounterRepository.php ├── DocumentRepositoryInterface.php ├── RepositoryInterface.php └── Stats │ └── MongoDB │ ├── CityRepository.php │ ├── ContinentRepository.php │ ├── CountryRepository.php │ ├── DayRepository.php │ ├── HourRepository.php │ ├── MinuteRepository.php │ ├── MongoDBStatsRepository.php │ ├── MonthRepository.php │ ├── PageContinentRepository.php │ ├── PageCountryRepository.php │ ├── PageRepository.php │ ├── RegionRepository.php │ ├── SecondRepository.php │ ├── WeekRepository.php │ └── YearRepository.php ├── Resources ├── config │ ├── command.yml │ ├── geolocation.yml │ ├── repository.yml │ ├── statistics.yml │ ├── storage.yml │ └── viewcounter.yml └── doc │ ├── images │ ├── geolocation-data-washington.png │ ├── geolocation-data.png │ ├── geolocation-view-date.png │ ├── monthly-views-2018.png │ ├── statistical-data-2018.png │ └── statistical-data-first-week-january-2018.png │ └── readme │ ├── geolocation.md │ ├── graph-google-charts.md │ ├── installation.md │ ├── statistics-computer.md │ ├── statistics-finder.md │ ├── tools-command-cleanup.md │ ├── tools-command-stats-converter.md │ └── usage-step-1-5.md ├── Statistics ├── Date.php ├── Day.php ├── Hour.php ├── HourTrait.php ├── Minute.php ├── MinuteTrait.php ├── Month.php ├── Page.php ├── Second.php ├── SecondTrait.php ├── ViewDateTrait.php ├── Week.php └── Year.php ├── Storage ├── Database │ └── MongoDB │ │ ├── DocumentStorageInterface.php │ │ └── MongoDBStorage.php └── Filesystem │ ├── FilesystemStorage.php │ └── FilesystemStorageInterface.php ├── TchoulomViewCounterBundle.php ├── Tests ├── BaseTest.php ├── Counter │ ├── AbstractViewCounterTest.php │ └── ViewCounterTest.php ├── DependencyInjection │ └── TchoulomViewCounterExtensionTest.php └── Entity │ └── ViewCounterTest.php ├── Util ├── Date.php └── ReflectionExtractor.php ├── composer.json └── phpunit.xml.dist /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | /.idea 3 | 4 | 5 | -------------------------------------------------------------------------------- /Adapter/Geolocator/GeolocatorAdapter.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Adapter\Geolocator; 16 | 17 | use Tchoulom\ViewCounterBundle\Exception\RuntimeException; 18 | use Tchoulom\ViewCounterBundle\Util\ReflectionExtractor; 19 | 20 | /** 21 | * Class GeolocatorAdapter 22 | */ 23 | class GeolocatorAdapter implements GeolocatorAdapterInterface 24 | { 25 | /** 26 | * The given Geolocator service. 27 | * This service must implements the "GeolocatorAdapterInterface". 28 | * 29 | * @var GeolocatorAdapterInterface|null 30 | */ 31 | protected $geolocator; 32 | 33 | /** 34 | * The criteria is not supported message. 35 | * 36 | * @var string 37 | */ 38 | protected const GEOLOCATOR_NOT_SUPPORTED_MSG = '%s service must implement the "Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface".'; 39 | 40 | /** 41 | * GeolocatorAdapter constructor. 42 | * 43 | * @param GeolocatorAdapterInterface|null $geolocator The given Geolocator service 44 | */ 45 | public function __construct(?GeolocatorAdapterInterface $geolocator) 46 | { 47 | if (!$this->supports($geolocator)) { 48 | throw new RuntimeException(sprintf(self::GEOLOCATOR_NOT_SUPPORTED_MSG, 49 | ReflectionExtractor::getFullClassName($geolocator))); 50 | } 51 | 52 | $this->geolocator = $geolocator; 53 | } 54 | 55 | /** 56 | * Gets the Geolocator service. 57 | * 58 | * @return GeolocatorAdapterInterface|null The Geolocator service 59 | */ 60 | public function getGeolocator(): ?GeolocatorAdapterInterface 61 | { 62 | return $this->geolocator; 63 | } 64 | 65 | /** 66 | * The record returned. 67 | * 68 | * @return mixed The record 69 | */ 70 | public function getRecord() 71 | { 72 | return $this->geolocator->getRecord(); 73 | } 74 | 75 | /** 76 | * Gets the continent name. 77 | * 78 | * @return string The continent name 79 | */ 80 | public function getContinent(): string 81 | { 82 | return $this->geolocator->getContinent(); 83 | } 84 | 85 | /** 86 | * Gets the country name. 87 | * 88 | * @return string The country name 89 | */ 90 | public function getCountry(): string 91 | { 92 | return $this->geolocator->getCountry(); 93 | } 94 | 95 | /** 96 | * Gets the region name. 97 | * 98 | * @return string The region name 99 | */ 100 | public function getRegion(): string 101 | { 102 | return $this->geolocator->getRegion(); 103 | } 104 | 105 | /** 106 | * Gets the city name. 107 | * 108 | * @return string The city name 109 | */ 110 | public function getCity(): string 111 | { 112 | return $this->geolocator->getCity(); 113 | } 114 | 115 | /** 116 | * Allows to check if we can geolocate. 117 | * 118 | * @return bool Can use the Geolocator service? 119 | */ 120 | public function canGeolocate(): bool 121 | { 122 | return $this->getGeolocator() instanceof GeolocatorAdapterInterface; 123 | } 124 | 125 | /** 126 | * Checks if the given Geolocator service is supported. 127 | * 128 | * @param GeolocatorAdapterInterface|null $geolocator The given Geolocator service. 129 | * 130 | * @return bool Is the given Geolocator service supported? 131 | */ 132 | public function supports(?GeolocatorAdapterInterface $geolocator): bool 133 | { 134 | // The case where the Geolocator geolocator_id is not used in the project. 135 | if (null === $geolocator) { 136 | return true; 137 | } 138 | 139 | return $geolocator instanceof GeolocatorAdapterInterface; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Adapter/Geolocator/GeolocatorAdapterInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Adapter\Storage; 16 | 17 | /** 18 | * Class StorageAdapter 19 | */ 20 | class StorageAdapter implements StorageAdapterInterface 21 | { 22 | /** 23 | * @var StorageAdapterInterface The storage service. 24 | */ 25 | protected $storer; 26 | 27 | /** 28 | * StorageAdapter constructor. 29 | * 30 | * @param StorageAdapterInterface $storer The storage service. 31 | */ 32 | public function __construct(StorageAdapterInterface $storer) 33 | { 34 | $this->storer = $storer; 35 | } 36 | 37 | /** 38 | * Saves the statistics. 39 | * 40 | * @param $stats 41 | */ 42 | public function save($stats) 43 | { 44 | $this->storer->save($stats); 45 | } 46 | 47 | /** 48 | * Loads the contents. 49 | * 50 | * @return mixed 51 | */ 52 | public function loadContents() 53 | { 54 | return $this->storer->loadContents(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Adapter/Storage/StorageAdapterInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Adapter\Storage; 16 | 17 | 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Model\ViewCountable; 20 | 21 | /** 22 | * Interface StorageAdapterInterface 23 | * 24 | * @package Tchoulom\ViewCounterBundle\Adapter\Storage 25 | */ 26 | interface StorageAdapterInterface 27 | { 28 | /** 29 | * Saves the statistics. 30 | * 31 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 32 | */ 33 | public function save(ViewCounterInterface $viewcounter); 34 | } 35 | -------------------------------------------------------------------------------- /Builder/FileStatsBuilder.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Builder; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Model\ViewCountable; 20 | use Tchoulom\ViewCounterBundle\Statistics\Page; 21 | use Tchoulom\ViewCounterBundle\Util\ReflectionExtractor; 22 | 23 | /** 24 | * Class FileStatsBuilder 25 | * 26 | * Builds the file statistics. 27 | */ 28 | class FileStatsBuilder 29 | { 30 | /** 31 | * The contents. 32 | * 33 | * @var array 34 | */ 35 | protected $contents; 36 | 37 | /** 38 | * The given class. 39 | * 40 | * @var string 41 | */ 42 | protected $class; 43 | 44 | /** 45 | * The page. 46 | * 47 | * @var Page 48 | */ 49 | protected $page; 50 | 51 | /** 52 | * The stats. 53 | * 54 | * @var array 55 | */ 56 | protected $stats = []; 57 | 58 | /** 59 | * The Geolocator. 60 | * 61 | * @var GeolocatorAdapterInterface 62 | */ 63 | protected $geolocator; 64 | 65 | /** 66 | * FileStatsBuilder constructor. 67 | * 68 | * @param GeolocatorAdapterInterface $geolocator 69 | */ 70 | public function __construct(GeolocatorAdapterInterface $geolocator) 71 | { 72 | $this->geolocator = $geolocator; 73 | } 74 | 75 | /** 76 | * Gets the contents. 77 | * 78 | * @return array 79 | */ 80 | public function getContents(): array 81 | { 82 | return $this->contents; 83 | } 84 | 85 | /** 86 | * Sets the contents. 87 | * 88 | * @param array $contents 89 | * 90 | * @return self 91 | */ 92 | public function setContents(array $contents): self 93 | { 94 | $this->contents = $contents; 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Gets the class name. 101 | * 102 | * @return string 103 | */ 104 | public function getClass() 105 | { 106 | return $this->class; 107 | } 108 | 109 | /** 110 | * Sets the class name. 111 | * 112 | * @param string $class 113 | * 114 | * @return self 115 | */ 116 | public function setClass(string $class): self 117 | { 118 | $this->class = $class; 119 | 120 | return $this; 121 | } 122 | 123 | /** 124 | * Gets the page. 125 | * 126 | * @return Page 127 | */ 128 | public function getPage(): Page 129 | { 130 | return $this->page; 131 | } 132 | 133 | /** 134 | * Sets the page. 135 | * 136 | * @param Page $page 137 | * 138 | * @return self 139 | */ 140 | public function setPage(Page $page): self 141 | { 142 | $this->page = $page; 143 | 144 | return $this; 145 | } 146 | 147 | /** 148 | * Gets the stats. 149 | * 150 | * @return array 151 | */ 152 | public function getStats(): array 153 | { 154 | return $this->stats; 155 | } 156 | 157 | /** 158 | * Sets the stats. 159 | * 160 | * @param array $stats 161 | * 162 | * @return self 163 | */ 164 | public function setStats(array $stats): self 165 | { 166 | $this->stats = $stats; 167 | 168 | return $this; 169 | } 170 | 171 | /** 172 | * Builds the stats. 173 | * 174 | * @param array $contents The contents. 175 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 176 | * 177 | * @return self 178 | */ 179 | public function build(array $contents, ViewCounterInterface $viewcounter): self 180 | { 181 | $page = $viewcounter->getPage(); 182 | $this->contents = $contents; 183 | $this->class = ReflectionExtractor::getClassNamePluralized($page); 184 | $this->stats = $this->buildPage($page, $viewcounter); 185 | 186 | return $this; 187 | } 188 | 189 | /** 190 | * Builds the page. 191 | * 192 | * @param ViewCountable $pageRef The page ref. 193 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 194 | * 195 | * @return array 196 | */ 197 | public function buildPage(ViewCountable $pageRef, ViewCounterInterface $viewcounter): array 198 | { 199 | $pageId = $pageRef->getId(); 200 | 201 | if (isset($this->contents[$this->class][$pageId])) { 202 | $page = $this->contents[$this->class][$pageId]; 203 | } else { 204 | $page = new Page($pageId); 205 | } 206 | 207 | $page->buildYear($viewcounter); 208 | if ($this->geolocator->canGeolocate()) { 209 | $page->buildCountry($this->geolocator, $viewcounter); 210 | } 211 | 212 | $this->contents[$this->class][$pageId] = $page; 213 | $this->page = $page; 214 | 215 | return $this->contents; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /Command/ViewcounterCleanupCommand.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Command; 16 | 17 | use Symfony\Component\Console\Input\InputArgument; 18 | use Symfony\Component\Console\Input\InputOption; 19 | 20 | /** 21 | * The Viewcounter cleanup Command. 22 | * 23 | * Class CleanupViewcounterCommand 24 | */ 25 | class ViewcounterCleanupCommand extends AbstractCommand 26 | { 27 | /** 28 | * @var string confirmation before cleanup. 29 | */ 30 | protected const CLEANUP_CONFIRMED = 'yes'; 31 | 32 | /** 33 | * @var bool determines if the given value is correct 34 | */ 35 | protected $check = true; 36 | 37 | /** 38 | * @var string The cleanup message. 39 | */ 40 | protected const CLEANUP_MSG = 'Cleanup the viewcounter data'; 41 | 42 | /** 43 | * @var string Deleting viewcounter message. 44 | */ 45 | protected const DELETING_VIEWCOUNTER_DATA_MSG = 'Deleting viewcounter data...'; 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | protected function configure() 51 | { 52 | $this 53 | ->setName('tchoulom:viewcounter:cleanup') 54 | ->setDescription( 55 | 'Deletes viewcounter data from the database according to the given criteria.' 56 | ) 57 | ->setDefinition(array( 58 | new InputOption( 59 | 'min', null, InputOption::VALUE_OPTIONAL, 60 | "The option 'min' allows to remove viewcounters entities where view date greater than or equals the given value (Example: 1s). 61 | If only this option is set, then the viewcounters records meeting this criteria will be deleted. 62 | " 63 | ), 64 | new InputOption( 65 | 'max', null, InputOption::VALUE_OPTIONAL, 66 | "The option 'max' allows to remove viewcounters entities where view date less than or equals the given value (Example: 7m). 67 | If only this option is set, then the viewcounters records meeting this criteria will be deleted. 68 | " 69 | ), 70 | new InputOption( 71 | self::AUTO_APPROVE, null, InputOption::VALUE_OPTIONAL, 72 | "The argument 'auto-approve' allows interactive questions to be approved automatically. 73 | If the 'auto-approve' option is equal to true, interactive questions will be automatically approved. 74 | If the 'auto-approve' option is equal to false, interactive questions will not be automatically approved. 75 | By default the value of the 'auto-approve' option is equal to false. 76 | " 77 | ), 78 | )) 79 | ->setHelp(' 80 | bin/console tchoulom:viewcounter:cleanup --min=3y 81 | 82 | Deletes viewcounter data from the database according to the given criteria. 83 | 84 | Examples of date interval: 85 | 86 | "s" => "second" 87 | "m" => "minute" 88 | "h" => "hour" 89 | "d" => "day" 90 | "w" => "week" 91 | "M" => "month" 92 | "y" => "year" 93 | 94 | bin/console tchoulom:viewcounter:cleanup --auto-approve=true 95 | 96 | 97 | ' . self::SEE_DOCUMENTATION_MSG . '' 98 | ); 99 | } 100 | 101 | /** 102 | * Executes the cleanup Command. 103 | * 104 | * @return int Does the command end with success or failure? 105 | * 106 | * @throws \Exception 107 | */ 108 | protected function doExecute(): int 109 | { 110 | return $this->cleanup(); 111 | } 112 | 113 | /** 114 | * Handles cleanup viewcounter data. 115 | * 116 | * @return int Does the command end with success or failure? 117 | * 118 | * @throws \Exception 119 | */ 120 | protected function cleanup(): int 121 | { 122 | $this->io->title(self::CLEANUP_MSG); 123 | 124 | $min = $this->input->getOption('min'); 125 | $max = $this->input->getOption('max'); 126 | 127 | if (null !== $min && false === $this->checkDuration($min)) { 128 | $this->io->error(sprintf(self::CRITERIA_NOT_SUPPORTED_MSG, "'$min'")); 129 | $this->check = false; 130 | } 131 | if (null !== $max && false === $this->checkDuration($max)) { 132 | $this->io->error(sprintf(self::CRITERIA_NOT_SUPPORTED_MSG, "'$max'")); 133 | $this->check = false; 134 | } 135 | 136 | if (false === $this->check) { 137 | $this->io->writeln(''); 138 | $this->io->note(self::SEE_DOCUMENTATION_MSG); 139 | $this->io->writeln(''); 140 | $this->io->comment(self::NO_CHANGE_MADE_MSG); 141 | 142 | return self::FAILURE; 143 | } 144 | 145 | $confirmCleanup = $this->tryAutoApprove(self::ASK_QUESTION_MSG); 146 | 147 | if (self::CLEANUP_CONFIRMED === $confirmCleanup) { 148 | $this->io->writeln(self::DELETING_VIEWCOUNTER_DATA_MSG); 149 | 150 | $min = (null === $min) ? $min : $this->subtractDuration($min); 151 | $max = (null === $max) ? $max : $this->subtractDuration($max); 152 | 153 | $rowsDeleted = $this->counterManager->cleanup($min, $max); 154 | $this->writeRowsDeletedResponse($rowsDeleted); 155 | 156 | return self::SUCCESS; 157 | } else { 158 | $this->io->writeln('' . self::NO_CHANGE_MADE_MSG . ''); 159 | 160 | return self::SUCCESS; 161 | } 162 | 163 | $this->io->error(self::ERROR_OCCURRED_MSG); 164 | $this->io->writeln('' . self::NO_CHANGE_MADE_MSG . ''); 165 | 166 | return self::FAILURE; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Compute/StatsComputer.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Compute; 16 | 17 | /** 18 | * Class StatsComputer 19 | */ 20 | class StatsComputer 21 | { 22 | /** 23 | * Computes the min value of the statistics. 24 | * 25 | * @param array $stats 26 | * 27 | * @return array|mixed|null 28 | */ 29 | public function computeMinValue(array $stats) 30 | { 31 | if (empty($stats)) { 32 | return null; 33 | } 34 | 35 | array_multisort(array_map(function ($element) { 36 | return $element[1]; 37 | }, $stats), SORT_ASC, $stats); 38 | 39 | $minValues = []; 40 | $min = $stats[0]; 41 | foreach ($stats as $statsPoint) { 42 | if ($statsPoint[1] > $min[1]) { 43 | break; 44 | } 45 | 46 | $minValues[] = $statsPoint; 47 | } 48 | 49 | if (count($minValues) == 1) { 50 | $minValues = $min; 51 | } 52 | 53 | return $minValues; 54 | } 55 | 56 | /** 57 | * Computes the max value of the statistics. 58 | * 59 | * @param array $stats 60 | * 61 | * @return array|mixed|null 62 | */ 63 | public function computeMaxValue(array $stats) 64 | { 65 | if (empty($stats)) { 66 | return null; 67 | } 68 | 69 | array_multisort(array_map(function ($element) { 70 | return $element[1]; 71 | }, $stats), SORT_DESC, $stats); 72 | 73 | $maxValues = []; 74 | $max = $stats[0]; 75 | foreach ($stats as $statsPoint) { 76 | if ($statsPoint[1] < $max[1]) { 77 | break; 78 | } 79 | 80 | $maxValues[] = $statsPoint; 81 | } 82 | 83 | if (count($maxValues) == 1) { 84 | $maxValues = $max; 85 | } 86 | 87 | return $maxValues; 88 | } 89 | 90 | /** 91 | * Computes the average of the statistics. 92 | * The average is the sum of the values ​​of the statistical series divided by the number of values. 93 | * 94 | * @param array $stats 95 | * 96 | * @return float|int|null 97 | */ 98 | public function computeAverage(array $stats) 99 | { 100 | if (empty($stats)) { 101 | return null; 102 | } 103 | 104 | $statsValues = array_map(function ($statsPoint) { 105 | return $statsPoint[1]; 106 | }, $stats); 107 | 108 | $average = array_sum($statsValues) / count($statsValues); 109 | 110 | return $average; 111 | } 112 | 113 | /** 114 | * Computes the range of the statistics. 115 | * The range is the difference between the highest number and the lowest number. 116 | * 117 | * @param array $stats 118 | * 119 | * @return mixed|null 120 | */ 121 | public function computeRange(array $stats) 122 | { 123 | if (empty($stats)) { 124 | return null; 125 | } 126 | 127 | $statsValues = array_map(function ($statsPoint) { 128 | return $statsPoint[1]; 129 | }, $stats); 130 | 131 | $max = max($statsValues); 132 | $min = min($statsValues); 133 | $range = $max - $min; 134 | 135 | return $range; 136 | } 137 | 138 | /** 139 | * Computes the mode of the statistics. 140 | * The mode is the number that is in the array the most times. 141 | * 142 | * @param array $stats 143 | * 144 | * @return mixed|null 145 | */ 146 | public function computeMode(array $stats) 147 | { 148 | if (empty($stats)) { 149 | return null; 150 | } 151 | 152 | $statsValues = array_map(function ($statsPoint) { 153 | return $statsPoint[1]; 154 | }, $stats); 155 | 156 | $statsValuesCount = array_count_values($statsValues); 157 | $mode = array_search(max($statsValuesCount), $statsValuesCount); 158 | 159 | return $mode; 160 | } 161 | 162 | /** 163 | * Computes the median of the statistics. 164 | * The median is the middle value after the numbers are sorted smallest to largest. 165 | * 166 | * @param array $stats 167 | * 168 | * @return float|int|null 169 | */ 170 | public function computeMedian(array $stats) 171 | { 172 | if (empty($stats)) { 173 | return null; 174 | } 175 | 176 | $statsValues = array_map(function ($statsPoint) { 177 | return $statsPoint[1]; 178 | }, $stats); 179 | 180 | sort($statsValues); 181 | 182 | $statsValuesCount = count($statsValues); 183 | $statsValuesMaxKey = $statsValuesCount - 1; 184 | 185 | if (0 == $statsValuesCount % 2) { 186 | $medianKey1 = $statsValuesMaxKey / 2; 187 | $medianKey2 = $medianKey1 + 1; 188 | 189 | $median1 = $statsValues[$medianKey1]; 190 | $median2 = $statsValues[$medianKey2]; 191 | $median = ($median1 + $median2) / 2; 192 | } else { 193 | $medianKey = $statsValuesMaxKey / 2; 194 | $median = $statsValues[$medianKey]; 195 | } 196 | 197 | return $median; 198 | } 199 | 200 | /** 201 | * Count the number of values in the statistical series. 202 | * 203 | * @param array $stats 204 | * 205 | * @return int 206 | */ 207 | public function count(array $stats) 208 | { 209 | return count($stats); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/ViewcounterPass.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\DependencyInjection\Compiler; 16 | 17 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 18 | use Symfony\Component\DependencyInjection\ContainerBuilder; 19 | use Symfony\Component\DependencyInjection\Definition; 20 | use Tchoulom\ViewCounterBundle\TchoulomViewCounterBundle; 21 | 22 | /** 23 | * Class ViewcounterPass. 24 | */ 25 | class ViewcounterPass implements CompilerPassInterface 26 | { 27 | /** 28 | * @param ContainerBuilder $container 29 | */ 30 | public function process(ContainerBuilder $container) 31 | { 32 | $configs = $container->getExtensionConfig('tchoulom_view_counter'); 33 | 34 | $viewcounterNode = $configs[0]['view_counter']; 35 | $statsNode = $configs[0]['statistics']; 36 | $storageNode = $configs[0]['storage'] ?? null; 37 | $geolocationNode = $configs[0]['geolocation'] ?? null; 38 | 39 | $viewcounterNodeDefinition = $container->getDefinition('tchoulom.viewcounter_node_config'); 40 | $statisticsNodeDefinition = $container->getDefinition('tchoulom.statistics_node_config'); 41 | 42 | $viewcounterNodeDefinition->replaceArgument(0, $viewcounterNode); 43 | $statisticsNodeDefinition->replaceArgument(0, $statsNode); 44 | 45 | if (isset($storageNode['engine'])) { 46 | $storerDefinition = $this->getStorageEngineDefinition($container, $storageNode['engine']); 47 | 48 | $storageAdapterDefinition = $container->getDefinition('tchoulom.viewcounter.storage_adapter'); 49 | $storageAdapterDefinition->replaceArgument(0, $storerDefinition); 50 | 51 | $statsConverterDefinition = $container->getDefinition('tchoulom.viewcounter.stats_converter'); 52 | $statsConverterDefinition->replaceArgument(0, $storerDefinition); 53 | 54 | if (TchoulomViewCounterBundle::MONGODB_STORAGE_ENGINE_NAME === $storageNode['engine']) { 55 | $doctrineMongoDBODMDefinition = $container->getDefinition('doctrine_mongodb.odm.default_document_manager'); 56 | $mongoDBStorageDefinition = $container->getDefinition('tchoulom.viewcounter.mongodb_storage'); 57 | $mongoDBStorageDefinition->replaceArgument(0, $doctrineMongoDBODMDefinition); 58 | } 59 | } 60 | 61 | if (isset($geolocationNode['geolocator_id'])) { 62 | $geolocatorAdapterDefinition = $container->getDefinition('tchoulom.viewcounter.geolocator_adapter'); 63 | $geolocatorDefinition = $container->getDefinition($geolocationNode['geolocator_id']); 64 | $geolocatorAdapterDefinition->replaceArgument(0, $geolocatorDefinition); 65 | } 66 | } 67 | 68 | /** 69 | * Gets the storage engine definition. 70 | * 71 | * @param ContainerBuilder $container The container. 72 | * @param string $storageEngine The storage engine. 73 | * 74 | * @return Definition 75 | */ 76 | public function getStorageEngineDefinition(ContainerBuilder $container, string $storageEngine): Definition 77 | { 78 | if (in_array($storageEngine, ['filesystem', 'mongodb'])) { 79 | return $container->getDefinition('tchoulom.viewcounter.' . $storageEngine . '_storage'); 80 | } 81 | 82 | return $container->getDefinition($storageEngine); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\DependencyInjection; 16 | 17 | use Symfony\Component\Config\Definition\Builder\TreeBuilder; 18 | use Symfony\Component\Config\Definition\ConfigurationInterface; 19 | use Tchoulom\ViewCounterBundle\TchoulomViewCounterBundle; 20 | 21 | /** 22 | * This is the class that validates and merges configuration from your app/config files. 23 | * 24 | * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html} 25 | */ 26 | class Configuration implements ConfigurationInterface 27 | { 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | public function getConfigTreeBuilder(): TreeBuilder 32 | { 33 | $treeBuilder = new TreeBuilder('tchoulom_view_counter'); 34 | $supportedInterval = implode(', ', TchoulomViewCounterBundle::SUPPORTED_STRATEGY); 35 | 36 | $treeBuilder->getRootNode() 37 | ->children() 38 | ->arrayNode('view_counter') 39 | ->isRequired()->info('Allows to define the Viewcounter information.') 40 | ->children() 41 | ->scalarNode('view_strategy')->defaultValue('daily_view')->info('Defines the view strategy.') 42 | ->validate() 43 | ->ifNotInArray(TchoulomViewCounterBundle::SUPPORTED_STRATEGY) 44 | ->thenInvalid('Invalid view strategy name %s. You must choose one of the following values: '. $supportedInterval) 45 | ->end() 46 | ->end() 47 | ->end() 48 | ->end() 49 | ->arrayNode('statistics') 50 | ->children() 51 | ->booleanNode('enabled')->isRequired()->defaultValue(false)->info('Defines whether to use statistics.')->end() 52 | ->scalarNode('stats_file_name')->isRequired()->info('Defines the name of the statistics file.')->end() 53 | ->scalarNode('stats_file_extension')->isRequired()->info('Defines the extension of the statistics file.')->end() 54 | ->end() 55 | ->end() 56 | ->arrayNode('storage') 57 | ->children() 58 | ->scalarNode('engine')->info('Allows to define the Storage engine name.')->end() 59 | ->end() 60 | ->end() 61 | ->arrayNode('geolocation') 62 | ->children() 63 | ->scalarNode('geolocator_id')->info('Allows to define the Geolocation service identifier.') 64 | ->end() 65 | ->end() 66 | ->end() 67 | ->end(); 68 | 69 | return $treeBuilder; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /DependencyInjection/TchoulomViewCounterExtension.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\DependencyInjection; 16 | 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | use Symfony\Component\Config\FileLocator; 19 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; 20 | use Symfony\Component\DependencyInjection\Loader; 21 | 22 | /** 23 | * This is the class that loads and manages your bundle configuration. 24 | * 25 | * @link http://symfony.com/doc/current/cookbook/bundles/extension.html 26 | */ 27 | class TchoulomViewCounterExtension extends Extension 28 | { 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | public function load(array $configs, ContainerBuilder $container) 33 | { 34 | $configuration = new Configuration(); 35 | 36 | $config = $this->processConfiguration($configuration, $configs); 37 | 38 | $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); 39 | 40 | $loader->load('viewcounter.yml'); 41 | $loader->load('storage.yml'); 42 | $loader->load('statistics.yml'); 43 | $loader->load('command.yml'); 44 | $loader->load('geolocation.yml'); 45 | $loader->load('repository.yml'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/AuditTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use DateTime; 18 | use DateTimeInterface; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | /** 22 | * Trait AuditTrait 23 | */ 24 | trait AuditTrait 25 | { 26 | #[MongoDB\Field(type: 'date', name: 'created_at')] 27 | protected $createdAt; 28 | 29 | #[MongoDB\Field(type: 'date', name: 'updated_at')] 30 | protected $updatedAt; 31 | 32 | #[MongoDB\PrePersist] 33 | public function onPrePersist(): void 34 | { 35 | $this->createdAt = new DateTime(); 36 | } 37 | 38 | #[MongoDB\PreUpdate] 39 | public function onPreUpdate(): void 40 | { 41 | $this->updatedAt = new DateTime(); 42 | } 43 | 44 | /** 45 | * @return DateTimeInterface 46 | */ 47 | public function getCreatedAt(): DateTimeInterface 48 | { 49 | return $this->createdAt; 50 | } 51 | 52 | /** 53 | * @return DateTimeInterface 54 | */ 55 | public function getUpdatedAt(): DateTimeInterface 56 | { 57 | return $this->updatedAt; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/City.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 17 | 18 | use Doctrine\Common\Collections\ArrayCollection; 19 | use Doctrine\Common\Collections\Collection; 20 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 21 | 22 | #[MongoDB\Document(collection: 'city', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\CityRepository')] 23 | #[MongoDB\HasLifecycleCallbacks] 24 | class City 25 | { 26 | use ViewTrait; 27 | use AuditTrait; 28 | 29 | #[MongoDB\Id] 30 | private $id; 31 | 32 | #[MongoDB\Field(type: 'string')] 33 | protected $name; 34 | 35 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Region', name: 'region_id', inversedBy: 'cities')] 36 | protected $region; 37 | 38 | /** 39 | * Gets Id. 40 | * 41 | * @return int 42 | */ 43 | public function getId(): int 44 | { 45 | return $this->id; 46 | } 47 | 48 | /** 49 | * Gets Name. 50 | * 51 | * @return string 52 | */ 53 | public function getName(): string 54 | { 55 | return $this->name; 56 | } 57 | 58 | /** 59 | * Sets Name. 60 | * 61 | * @param string $name 62 | * 63 | * @return self 64 | */ 65 | public function setName(string $name): self 66 | { 67 | $this->name = $name; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Gets Region. 74 | * 75 | * @return Region 76 | */ 77 | public function getRegion(): Region 78 | { 79 | return $this->region; 80 | } 81 | 82 | /** 83 | * Sets Region. 84 | * 85 | * @param Region $region 86 | * 87 | * @return self 88 | */ 89 | public function setRegion(Region $region): self 90 | { 91 | $this->region = $region; 92 | 93 | return $this; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Continent.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'continent', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\ContinentRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Continent 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\PageContinent', mappedBy: 'continent')] 35 | protected $pageContinents; 36 | 37 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Country', mappedBy: 'continent', cascade: ['persist', 'remove'])] 38 | protected $countries; 39 | 40 | /** 41 | * Page constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->pageContinents = new ArrayCollection(); 46 | $this->countries = new ArrayCollection(); 47 | } 48 | 49 | /** 50 | * Gets Id. 51 | * 52 | * @return int 53 | */ 54 | public function getId(): int 55 | { 56 | return $this->id; 57 | } 58 | 59 | /** 60 | * Gets Name. 61 | * 62 | * @return string 63 | */ 64 | public function getName(): string 65 | { 66 | return $this->name; 67 | } 68 | 69 | /** 70 | * Sets Name. 71 | * 72 | * @param string $name 73 | * 74 | * @return self 75 | */ 76 | public function setName(string $name): self 77 | { 78 | $this->name = $name; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Gets PageContinents. 85 | * 86 | * @return Collection|Country[] 87 | */ 88 | public function getPageContinents(): Collection 89 | { 90 | return $this->pageContinents; 91 | } 92 | 93 | /** 94 | * Add Page. 95 | * 96 | * @param Page $page The page. 97 | * 98 | * @return self 99 | */ 100 | public function addPageContinent(Page $page): self 101 | { 102 | if (!$this->pageContinents->contains($page)) { 103 | $this->pageContinents[] = $page; 104 | // not needed for persistence, just keeping both sides in sync 105 | // $page->addPageContinent($this); 106 | } 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * Remove Page. 113 | * 114 | * @param Page $page The page. 115 | * 116 | * @return self 117 | */ 118 | public function removePageContinent(Page $page): self 119 | { 120 | if ($this->pageContinents->contains($page)) { 121 | $this->pageContinents->removeElement($page); 122 | // not needed for persistence, just keeping both sides in sync 123 | // $page->removePageContinent($this); 124 | } 125 | 126 | return $this; 127 | } 128 | 129 | /** 130 | * Gets Countries. 131 | * 132 | * @return Collection|Country[] 133 | */ 134 | public function getCountries(): Collection 135 | { 136 | return $this->countries; 137 | } 138 | 139 | /** 140 | * Add Country. 141 | * 142 | * @param Country $country 143 | * 144 | * @return self 145 | */ 146 | public function addCountry(Country $country): self 147 | { 148 | if (!$this->countries->contains($country)) { 149 | $this->countries[] = $country; 150 | $country->setContinent($this); 151 | } 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Remove Country. 158 | * 159 | * @param Country $country 160 | * 161 | * @return self 162 | */ 163 | public function removeCountry(Country $country): self 164 | { 165 | if ($this->countries->contains($country)) { 166 | $this->countries->removeElement($country); 167 | } 168 | 169 | return $this; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Country.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'country', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\CountryRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Country 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\PageCountry', mappedBy: 'country')] 35 | protected $pageCountries; 36 | 37 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Continent', name: 'continent_id', inversedBy: 'countries')] 38 | protected $continent; 39 | 40 | /** 41 | * Country constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->pageCountries = new ArrayCollection(); 46 | } 47 | 48 | /** 49 | * Gets Id. 50 | * 51 | * @return int 52 | */ 53 | public function getId(): int 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * Gets Name. 60 | * 61 | * @return string 62 | */ 63 | public function getName(): string 64 | { 65 | return $this->name; 66 | } 67 | 68 | /** 69 | * Sets Name. 70 | * 71 | * @param string $name 72 | * 73 | * @return self 74 | */ 75 | public function setName(string $name): self 76 | { 77 | $this->name = $name; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Gets pageCountries. 84 | * 85 | * @return Collection|PageCountry[] 86 | */ 87 | public function getPageCountries(): Collection 88 | { 89 | return $this->pageCountries; 90 | } 91 | 92 | /** 93 | * Add Page. 94 | * 95 | * @param Page $page The page. 96 | * 97 | * @return self 98 | */ 99 | public function addPageCountry(Page $page): self 100 | { 101 | if (!$this->pageCountries->contains($page)) { 102 | $this->pageCountries[] = $page; 103 | // not needed for persistence, just keeping both sides in sync 104 | // $page->addPageCountry($this); 105 | } 106 | 107 | return $this; 108 | } 109 | 110 | /** 111 | * Remove Page. 112 | * 113 | * @param Page $page The page. 114 | * 115 | * @return self 116 | */ 117 | public function removePageCountry(Page $page): self 118 | { 119 | if ($this->pageCountries->contains($page)) { 120 | $this->pageCountries->removeElement($page); 121 | // not needed for persistence, just keeping both sides in sync 122 | // $page->removePageCountry($this); 123 | } 124 | 125 | return $this; 126 | } 127 | 128 | /** 129 | * Gets Continent. 130 | * 131 | * @return Continent The continent. 132 | */ 133 | public function getContinent(): Continent 134 | { 135 | return $this->continent; 136 | } 137 | 138 | /** 139 | * Sets the continent. 140 | * 141 | * @param Continent $continent The continent. 142 | * 143 | * @return self 144 | */ 145 | public function setContinent(Continent $continent): self 146 | { 147 | $this->continent = $continent; 148 | 149 | return $this; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Day.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'day', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\DayRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Day 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Week', name: 'week_id', inversedBy: 'days')] 35 | protected $week; 36 | 37 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Hour', mappedBy: 'day', cascade: ['persist', 'remove'])] 38 | protected $hours; 39 | 40 | /** 41 | * Day constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->hours = new ArrayCollection(); 46 | } 47 | 48 | /** 49 | * Gets Id. 50 | * 51 | * @return int 52 | */ 53 | public function getId(): int 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * Gets Name. 60 | * 61 | * @return string 62 | */ 63 | public function getName(): string 64 | { 65 | return $this->name; 66 | } 67 | 68 | /** 69 | * Sets Name. 70 | * 71 | * @param string $name 72 | * 73 | * @return self 74 | */ 75 | public function setName(string $name): self 76 | { 77 | $this->name = $name; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Gets Week. 84 | * 85 | * @return Week 86 | */ 87 | public function getWeek(): Week 88 | { 89 | return $this->week; 90 | } 91 | 92 | /** 93 | * Sets Week. 94 | * 95 | * @param Week $week 96 | * 97 | * @return self 98 | */ 99 | public function setWeek(Week $week): self 100 | { 101 | $this->week = $week; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Gets Hours. 108 | * 109 | * @return Collection|Hour[] 110 | */ 111 | public function getHours(): Collection 112 | { 113 | return $this->hours; 114 | } 115 | 116 | /** 117 | * Add Hour. 118 | * 119 | * @param Hour $hour 120 | * 121 | * @return self 122 | */ 123 | public function addHour(Hour $hour): self 124 | { 125 | if (!$this->hours->contains($hour)) { 126 | $this->hours[] = $hour; 127 | $hour->setDay($this); 128 | } 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Remove Hour. 135 | * 136 | * @param Hour $hour 137 | * 138 | * @return self 139 | */ 140 | public function removeHour(Hour $hour): self 141 | { 142 | if ($this->hours->contains($hour)) { 143 | $this->hours->removeElement($hour); 144 | } 145 | 146 | return $this; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Hour.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'hour', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\HourRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Hour 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Day', name: 'day_id', inversedBy: 'hours')] 35 | protected $day; 36 | 37 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Minute', mappedBy: 'hour', cascade: ['persist', 'remove'])] 38 | protected $minutes; 39 | 40 | /** 41 | * Hour constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->minutes = new ArrayCollection(); 46 | } 47 | 48 | /** 49 | * Gets Id. 50 | * 51 | * @return int 52 | */ 53 | public function getId(): int 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * Gets Name. 60 | * 61 | * @return string 62 | */ 63 | public function getName(): string 64 | { 65 | return $this->name; 66 | } 67 | 68 | /** 69 | * Sets Name. 70 | * 71 | * @param string $name 72 | * 73 | * @return self 74 | */ 75 | public function setName(string $name): self 76 | { 77 | $this->name = $name; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Gets Day. 84 | * 85 | * @return Day 86 | */ 87 | public function getDay(): Day 88 | { 89 | return $this->day; 90 | } 91 | 92 | /** 93 | * Sets Day. 94 | * 95 | * @param Day $day 96 | * 97 | * @return self 98 | */ 99 | public function setDay(Day $day): self 100 | { 101 | $this->day = $day; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Gets Minutes. 108 | * 109 | * @return Collection|Minute[] 110 | */ 111 | public function getMinutes(): Collection 112 | { 113 | return $this->minutes; 114 | } 115 | 116 | /** 117 | * Add Minute. 118 | * 119 | * @param Minute $minute 120 | * 121 | * @return self 122 | */ 123 | public function addMinute(Minute $minute): self 124 | { 125 | if (!$this->minutes->contains($minute)) { 126 | $this->minutes[] = $minute; 127 | $minute->setHour($this); 128 | } 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Remove Minute. 135 | * 136 | * @param Minute $minute 137 | * 138 | * @return self 139 | */ 140 | public function removeMinute(Minute $minute): self 141 | { 142 | if ($this->minutes->contains($minute)) { 143 | $this->minutes->removeElement($minute); 144 | } 145 | 146 | return $this; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Minute.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'minute', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\MinuteRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Minute 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Hour', name: 'hour_id', inversedBy: 'minutes')] 35 | protected $hour; 36 | 37 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Second', mappedBy: 'minute', cascade: ['persist', 'remove'])] 38 | protected $seconds; 39 | 40 | /** 41 | * Minute constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->seconds = new ArrayCollection(); 46 | } 47 | 48 | /** 49 | * Gets Id. 50 | * 51 | * @return int 52 | */ 53 | public function getId(): int 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * Gets Name. 60 | * 61 | * @return string 62 | */ 63 | public function getName(): string 64 | { 65 | return $this->name; 66 | } 67 | 68 | /** 69 | * Sets Name. 70 | * 71 | * @param string $name 72 | * 73 | * @return self 74 | */ 75 | public function setName(string $name): self 76 | { 77 | $this->name = $name; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Gets Hour. 84 | * 85 | * @return Hour 86 | */ 87 | public function getHour(): Hour 88 | { 89 | return $this->hour; 90 | } 91 | 92 | /** 93 | * Sets Hour. 94 | * 95 | * @param Hour $hour 96 | * 97 | * @return self 98 | */ 99 | public function setHour(Hour $hour): self 100 | { 101 | $this->hour = $hour; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Gets Seconds. 108 | * 109 | * @return Collection|Second[] 110 | */ 111 | public function getSeconds(): Collection 112 | { 113 | return $this->seconds; 114 | } 115 | 116 | /** 117 | * Add Second. 118 | * 119 | * @param Second $second 120 | * 121 | * @return self 122 | */ 123 | public function addSecond(Second $second): self 124 | { 125 | if (!$this->seconds->contains($second)) { 126 | $this->seconds[] = $second; 127 | $second->setMinute($this); 128 | } 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Remove Second. 135 | * 136 | * @param Second $second 137 | * 138 | * @return self 139 | */ 140 | public function removeSecond(Second $second): self 141 | { 142 | if ($this->seconds->contains($second)) { 143 | $this->seconds->removeElement($second); 144 | } 145 | 146 | return $this; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Month.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'month', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\MonthRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Month 24 | { 25 | use NumberTrait; 26 | use ViewTrait; 27 | use AuditTrait; 28 | 29 | #[MongoDB\Id] 30 | private $id; 31 | 32 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Year', name: 'year_id', inversedBy: 'months')] 33 | protected $year; 34 | 35 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Week', mappedBy: 'month', cascade: ['persist', 'remove'])] 36 | protected $weeks; 37 | 38 | /** 39 | * Month constructor. 40 | */ 41 | public function __construct() 42 | { 43 | $this->weeks = new ArrayCollection(); 44 | } 45 | 46 | /** 47 | * Gets Id. 48 | * 49 | * @return int 50 | */ 51 | public function getId(): int 52 | { 53 | return $this->id; 54 | } 55 | 56 | /** 57 | * Gets Year. 58 | * 59 | * @return Year 60 | */ 61 | public function getYear(): Year 62 | { 63 | return $this->year; 64 | } 65 | 66 | /** 67 | * Sets Year. 68 | * 69 | * @param Year $year 70 | * 71 | * @return self 72 | */ 73 | public function setYear(Year $year): self 74 | { 75 | $this->year = $year; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * Gets Weeks. 82 | * 83 | * @return Collection|Week[] 84 | */ 85 | public function getWeeks(): Collection 86 | { 87 | return $this->weeks; 88 | } 89 | 90 | /** 91 | * Add Week. 92 | * 93 | * @param Week $week 94 | * 95 | * @return self 96 | */ 97 | public function addWeek(Week $week): self 98 | { 99 | if (!$this->weeks->contains($week)) { 100 | $this->weeks[] = $week; 101 | $week->setMonth($this); 102 | } 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Remove Week. 109 | * 110 | * @param Week $week 111 | * 112 | * @return self 113 | */ 114 | public function removeWeek(Week $week): self 115 | { 116 | if ($this->weeks->contains($week)) { 117 | $this->weeks->removeElement($week); 118 | } 119 | 120 | return $this; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/NumberTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 18 | 19 | /** 20 | * Trait NumberTrait 21 | */ 22 | trait NumberTrait 23 | { 24 | #[MongoDB\Field(type: 'integer')] 25 | protected $number; 26 | 27 | /** 28 | * Gets Number. 29 | * 30 | * @return int 31 | */ 32 | public function getNumber(): int 33 | { 34 | return $this->number; 35 | } 36 | 37 | /** 38 | * Sets Number. 39 | * 40 | * @param int $number 41 | * 42 | * @return self 43 | */ 44 | public function setNumber(int $number): self 45 | { 46 | $this->number = $number; 47 | 48 | return $this; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/PageContinent.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'pageContinent', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\PageContinentRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class PageContinent 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Page', name: 'page_id', inversedBy: 'pageContinents', nullable: false)] 32 | protected $page; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Continent', name: 'continent_id', inversedBy: 'pageContinents', nullable: false)] 35 | protected $continent; 36 | 37 | /** 38 | * Gets Id. 39 | * 40 | * @return int 41 | */ 42 | public function getId(): int 43 | { 44 | return $this->id; 45 | } 46 | 47 | /** 48 | * Gets the page. 49 | * 50 | * @return Page The page. 51 | */ 52 | public function getPage(): Page 53 | { 54 | return $this->page; 55 | } 56 | 57 | /** 58 | * Sets the page. 59 | * 60 | * @param Page $page The page. 61 | * 62 | * @return self 63 | */ 64 | public function setPage(Page $page): self 65 | { 66 | $this->page = $page; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Gets the continent. 73 | * 74 | * @return Continent The continent. 75 | */ 76 | public function getContinent(): Continent 77 | { 78 | return $this->continent; 79 | } 80 | 81 | /** 82 | * Sets the continent. 83 | * 84 | * @param Continent $continent The continent. 85 | * 86 | * @return self 87 | */ 88 | public function setContinent(Continent $continent): self 89 | { 90 | $this->continent = $continent; 91 | 92 | return $this; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/PageCountry.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'PageCountry', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\PageCountryRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class PageCountry 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Page', name: 'page_id', inversedBy: 'pageCountries', nullable: false)] 32 | protected $page; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Country', name: 'country_id', inversedBy: 'pageCountries', nullable: false)] 35 | protected $country; 36 | 37 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Region', mappedBy: 'country', cascade: ['persist', 'remove'])] 38 | protected $regions; 39 | 40 | /** 41 | * Country constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->regions = new ArrayCollection(); 46 | } 47 | 48 | /** 49 | * Gets Id. 50 | * 51 | * @return int 52 | */ 53 | public function getId(): int 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * Gets the page. 60 | * 61 | * @return Page The page. 62 | */ 63 | public function getPage(): Page 64 | { 65 | return $this->page; 66 | } 67 | 68 | /** 69 | * Sets the page. 70 | * 71 | * @param Page $page The page. 72 | * 73 | * @return self 74 | */ 75 | public function setPage(Page $page): self 76 | { 77 | $this->page = $page; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Gets the country. 84 | * 85 | * @return Country The country. 86 | */ 87 | public function getCountry(): Country 88 | { 89 | return $this->country; 90 | } 91 | 92 | /** 93 | * Sets the country. 94 | * 95 | * @param Country $country The country. 96 | * 97 | * @return self 98 | */ 99 | public function setCountry(Country $country): self 100 | { 101 | $this->country = $country; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Gets Regions. 108 | * 109 | * @return Collection|Region[] 110 | */ 111 | public function getRegions(): Collection 112 | { 113 | return $this->regions; 114 | } 115 | 116 | /** 117 | * Add Region. 118 | * 119 | * @param Region $region 120 | * 121 | * @return self 122 | */ 123 | public function addRegion(Region $region): self 124 | { 125 | if (!$this->regions->contains($region)) { 126 | $this->regions[] = $region; 127 | $region->setCountry($this); 128 | } 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Remove Region. 135 | * 136 | * @param Region $region 137 | * 138 | * @return self 139 | */ 140 | public function removeRegion(Region $region): self 141 | { 142 | if ($this->regions->contains($region)) { 143 | $this->regions->removeElement($region); 144 | } 145 | 146 | return $this; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Region.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'region', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\RegionRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Region 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\PageCountry', name: 'page_country_id', inversedBy: 'regions')] 35 | protected $pageCountry; 36 | 37 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\City', mappedBy: 'region', cascade: ['persist', 'remove'])] 38 | protected $cities; 39 | 40 | /** 41 | * Region constructor. 42 | */ 43 | public function __construct() 44 | { 45 | $this->cities = new ArrayCollection(); 46 | } 47 | 48 | /** 49 | * Gets Id. 50 | * 51 | * @return int 52 | */ 53 | public function getId(): int 54 | { 55 | return $this->id; 56 | } 57 | 58 | /** 59 | * Gets Name. 60 | * 61 | * @return string 62 | */ 63 | public function getName(): string 64 | { 65 | return $this->name; 66 | } 67 | 68 | /** 69 | * Sets Name. 70 | * 71 | * @param string $name 72 | * 73 | * @return self 74 | */ 75 | public function setName(string $name): self 76 | { 77 | $this->name = $name; 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Gets PageCountry. 84 | * 85 | * @return PageCountry 86 | */ 87 | public function getPageCountry(): PageCountry 88 | { 89 | return $this->pageCountry; 90 | } 91 | 92 | /** 93 | * Sets PageCountry. 94 | * 95 | * @param PageCountry $pageCountry 96 | * 97 | * @return self 98 | */ 99 | public function setPageCountry(PageCountry $pageCountry): self 100 | { 101 | $this->pageCountry = $pageCountry; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Gets Cities. 108 | * 109 | * @return Collection|City[] 110 | */ 111 | public function getCities(): Collection 112 | { 113 | return $this->cities; 114 | } 115 | 116 | /** 117 | * Add City. 118 | * 119 | * @param City $city 120 | * 121 | * @return self 122 | */ 123 | public function addCity(City $city): self 124 | { 125 | if (!$this->cities->contains($city)) { 126 | $this->cities[] = $city; 127 | $city->setRegion($this); 128 | } 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Remove City. 135 | * 136 | * @param City $city 137 | * 138 | * @return self 139 | */ 140 | public function removeCity(City $city): self 141 | { 142 | if ($this->cities->contains($city)) { 143 | $this->cities->removeElement($city); 144 | } 145 | 146 | return $this; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Second.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'second', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\SecondRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Second 24 | { 25 | use ViewTrait; 26 | use AuditTrait; 27 | 28 | #[MongoDB\Id] 29 | private $id; 30 | 31 | #[MongoDB\Field(type: 'string')] 32 | protected $name; 33 | 34 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Minute', name: 'minute_id', inversedBy: 'seconds')] 35 | protected $minute; 36 | 37 | /** 38 | * Gets Id. 39 | * 40 | * @return int 41 | */ 42 | public function getId(): int 43 | { 44 | return $this->id; 45 | } 46 | 47 | /** 48 | * Gets Name. 49 | * 50 | * @return string 51 | */ 52 | public function getName(): string 53 | { 54 | return $this->name; 55 | } 56 | 57 | /** 58 | * Sets Name. 59 | * 60 | * @param string $name 61 | * 62 | * @return self 63 | */ 64 | public function setName(string $name): self 65 | { 66 | $this->name = $name; 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Gets Minute. 73 | * 74 | * @return Minute 75 | */ 76 | public function getMinute(): Minute 77 | { 78 | return $this->minute; 79 | } 80 | 81 | /** 82 | * Sets Minute. 83 | * 84 | * @param Minute $minute 85 | * 86 | * @return self 87 | */ 88 | public function setMinute(Minute $minute): self 89 | { 90 | $this->minute = $minute; 91 | 92 | return $this; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/ViewTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 18 | 19 | /** 20 | * Trait ViewTrait 21 | * 22 | * @package Tchoulom\ViewCounterBundle\Document\Stats\MongoDB 23 | */ 24 | trait ViewTrait 25 | { 26 | #[MongoDB\Field(type: 'integer')] 27 | protected $views = 0; 28 | 29 | /** 30 | * Gets Views. 31 | * 32 | * @return int 33 | */ 34 | public function getViews(): int 35 | { 36 | return $this->views; 37 | } 38 | 39 | /** 40 | * Sets views. 41 | * 42 | * @param int $views 43 | * 44 | * @return self 45 | */ 46 | public function setViews(int $views): self 47 | { 48 | $this->views = $views; 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * Increase the views. 55 | * 56 | * @return self 57 | */ 58 | public function increaseViews(): self 59 | { 60 | $this->setViews(++$this->views); 61 | 62 | return $this; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Week.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'week', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\WeekRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Week 24 | { 25 | use NumberTrait; 26 | use ViewTrait; 27 | use AuditTrait; 28 | 29 | #[MongoDB\Id] 30 | private $id; 31 | 32 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Month', name: 'month_id', inversedBy: 'weeks')] 33 | protected $month; 34 | 35 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Day', mappedBy: 'week', cascade: ['persist', 'remove'])] 36 | protected $days; 37 | 38 | /** 39 | * Week constructor. 40 | */ 41 | public function __construct() 42 | { 43 | $this->days = new ArrayCollection(); 44 | } 45 | 46 | /** 47 | * Gets Id. 48 | * 49 | * @return int 50 | */ 51 | public function getId(): int 52 | { 53 | return $this->id; 54 | } 55 | 56 | /** 57 | * Gets Month. 58 | * 59 | * @return Month 60 | */ 61 | public function getMonth(): Month 62 | { 63 | return $this->month; 64 | } 65 | 66 | /** 67 | * Sets Month. 68 | * 69 | * @param Month $month 70 | * 71 | * @return self 72 | */ 73 | public function setMonth(Month $month): self 74 | { 75 | $this->month = $month; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * Gets Days. 82 | * 83 | * @return Collection|Day[] 84 | */ 85 | public function getDays(): Collection 86 | { 87 | return $this->days; 88 | } 89 | 90 | /** 91 | * Add Day. 92 | * 93 | * @param Day $day 94 | * 95 | * @return self 96 | */ 97 | public function addDay(Day $day): self 98 | { 99 | if (!$this->days->contains($day)) { 100 | $this->days[] = $day; 101 | $day->setWeek($this); 102 | } 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Remove Day. 109 | * 110 | * @param Day $day 111 | * 112 | * @return self 113 | */ 114 | public function removeDay(Day $day): self 115 | { 116 | if ($this->days->contains($day)) { 117 | $this->days->removeElement($day); 118 | } 119 | 120 | return $this; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Document/Stats/MongoDB/Year.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Document\Stats\MongoDB; 16 | 17 | use Doctrine\Common\Collections\ArrayCollection; 18 | use Doctrine\Common\Collections\Collection; 19 | use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; 20 | 21 | #[MongoDB\Document(collection: 'year', repositoryClass: 'Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB\YearRepository')] 22 | #[MongoDB\HasLifecycleCallbacks] 23 | class Year 24 | { 25 | use NumberTrait; 26 | use ViewTrait; 27 | use AuditTrait; 28 | 29 | #[MongoDB\Id] 30 | private $id; 31 | 32 | #[MongoDB\ReferenceOne(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Page', name: 'page_id', inversedBy: 'years')] 33 | protected $page; 34 | 35 | #[MongoDb\ReferenceMany(targetDocument: 'Tchoulom\ViewCounterBundle\Document\Stats\MongoDB\Month', mappedBy: 'year', cascade: ['persist', 'remove'])] 36 | protected $months; 37 | 38 | /** 39 | * Year constructor. 40 | */ 41 | public function __construct() 42 | { 43 | $this->months = new ArrayCollection(); 44 | } 45 | 46 | /** 47 | * Gets Id. 48 | * 49 | * @return int 50 | */ 51 | public function getId(): int 52 | { 53 | return $this->id; 54 | } 55 | 56 | /** 57 | * Gets Page. 58 | * 59 | * @return Page 60 | */ 61 | public function getPage(): Page 62 | { 63 | return $this->page; 64 | } 65 | 66 | /** 67 | * Sets Page. 68 | * 69 | * @param Page $page 70 | * 71 | * @return self 72 | */ 73 | public function setPage(Page $page): self 74 | { 75 | $this->page = $page; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * Gets Months. 82 | * 83 | * @return Collection|Month[] 84 | */ 85 | public function getMonths(): Collection 86 | { 87 | return $this->months; 88 | } 89 | 90 | /** 91 | * Add Month. 92 | * 93 | * @param Month $month 94 | * 95 | * @return self 96 | */ 97 | public function addMonth(Month $month): self 98 | { 99 | if (!$this->months->contains($month)) { 100 | $this->months[] = $month; 101 | $month->setYear($this); 102 | } 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Remove Month. 109 | * 110 | * @param Month $month 111 | * 112 | * @return self 113 | */ 114 | public function removeMonth(Month $month): self 115 | { 116 | if ($this->months->contains($month)) { 117 | $this->months->removeElement($month); 118 | } 119 | 120 | return $this; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ETL/StatsConverter.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\ETL; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Storage\StorageAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | 20 | /** 21 | * Class StatsConverter 22 | * 23 | * Converts ViewCounter entities to statistical data. 24 | */ 25 | class StatsConverter 26 | { 27 | /** 28 | * The StorageAdapter service. 29 | * 30 | * @var StorageAdapterInterface 31 | */ 32 | protected $storageAdapter; 33 | 34 | /** 35 | * StatsConverter constructor. 36 | * 37 | * @param StorageAdapterInterface $storageAdapter 38 | */ 39 | public function __construct(StorageAdapterInterface $storageAdapter) 40 | { 41 | $this->storageAdapter = $storageAdapter; 42 | } 43 | 44 | /** 45 | * Converts ViewCounter entities to statistical data. 46 | * 47 | * @param ViewCounterInterface $viewcounter The viewcounter entity to be converted into statistical data. 48 | * 49 | * @throws \ReflectionException 50 | */ 51 | public function convert(ViewCounterInterface $viewcounter) 52 | { 53 | $this->storageAdapter->save($viewcounter); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Entity/ViewCounter.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Entity; 16 | 17 | use DateTimeInterface; 18 | use Doctrine\ORM\Mapping as ORM; 19 | use Doctrine\ORM\Mapping\MappedSuperclass; 20 | use Doctrine\ORM\Mapping\HasLifecycleCallbacks; 21 | use Tchoulom\ViewCounterBundle\Model\ViewCountable; 22 | 23 | /** 24 | * ViewCounter Entity 25 | * 26 | * @ORM\MappedSuperclass 27 | * @ORM\HasLifecycleCallbacks 28 | */ 29 | #[ORM\MappedSuperclass] 30 | #[ORM\HasLifecycleCallbacks] 31 | abstract class ViewCounter implements ViewCounterInterface 32 | { 33 | /** 34 | * @ORM\Id 35 | * @ORM\Column(type="integer") 36 | * @ORM\GeneratedValue(strategy="AUTO") 37 | */ 38 | #[ORM\Id] 39 | #[ORM\Column(type: 'integer')] 40 | #[ORM\GeneratedValue(strategy: 'AUTO')] 41 | protected $id; 42 | 43 | /** 44 | * @var text $ip 45 | * 46 | * @ORM\Column(name="ip", type="text", nullable=false) 47 | */ 48 | #[ORM\Column(name: 'ip', type: 'text', nullable: false)] 49 | protected $ip; 50 | 51 | /** 52 | * @var DateTimeInterface 53 | * 54 | * @ORM\Column(name="view_date", type="datetime", nullable=false) 55 | */ 56 | #[ORM\Column(name: 'view_date', type: 'datetime', nullable: false)] 57 | protected $viewDate; 58 | 59 | /** 60 | * The property name. 61 | * 62 | * @var string 63 | */ 64 | protected $property; 65 | 66 | /** 67 | * Gets the ID 68 | * 69 | * @return integer 70 | */ 71 | public function getId() 72 | { 73 | return $this->id; 74 | } 75 | 76 | /** 77 | * Gets the IP 78 | * 79 | * @return text 80 | */ 81 | public function getIp() 82 | { 83 | return $this->ip; 84 | } 85 | 86 | /** 87 | * Sets viewDate 88 | * 89 | * @param $ip 90 | * 91 | * @return self 92 | */ 93 | public function setIp($ip) 94 | { 95 | $this->ip = $ip; 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Gets viewDate 102 | * 103 | * @return DateTimeInterface 104 | */ 105 | public function getViewDate() 106 | { 107 | return $this->viewDate; 108 | } 109 | 110 | /** 111 | * Sets viewDate 112 | * 113 | * @param DateTimeInterface $viewDate 114 | * 115 | * @return self 116 | */ 117 | public function setViewDate(DateTimeInterface $viewDate) 118 | { 119 | $this->viewDate = $viewDate; 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * Sets the property name. 126 | * 127 | * @param string $property 128 | * 129 | * @return self 130 | */ 131 | public function setProperty(string $property): self 132 | { 133 | $this->property = $property; 134 | 135 | return $this; 136 | } 137 | 138 | /** 139 | * Gets the property name. 140 | * 141 | * @return string 142 | */ 143 | public function getProperty(): string 144 | { 145 | return $this->property; 146 | } 147 | 148 | /** 149 | * Sets the page. 150 | * 151 | * @param ViewCountable $page 152 | * @param string $property 153 | * 154 | * @return self 155 | */ 156 | public function setPage(ViewCountable $page): self 157 | { 158 | $property = $this->getProperty(); 159 | $setPage = 'set' . ucfirst($property); 160 | $this->$setPage($page); 161 | 162 | return $this; 163 | } 164 | 165 | /** 166 | * Gets the page. 167 | * 168 | * @return ViewCountable|null 169 | */ 170 | public function getPage(): ?ViewCountable 171 | { 172 | $property = $this->getProperty(); 173 | $getPage = 'get' . ucfirst($property); 174 | $page = $this->$getPage(); 175 | 176 | return $page; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /Entity/ViewCounterInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Exception; 16 | 17 | /** 18 | * Interface ExceptionInterface 19 | */ 20 | interface ExceptionInterface 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /Exception/IOException.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Exception; 16 | 17 | /** 18 | * Class IOException 19 | */ 20 | class IOException extends RuntimeException implements IOExceptionInterface 21 | { 22 | /** 23 | * The path 24 | */ 25 | private $path; 26 | 27 | /** 28 | * IOException constructor. 29 | * 30 | * @param string $message 31 | * @param int $code 32 | * @param \Exception|null $previous 33 | * @param null $path 34 | */ 35 | public function __construct($message, $code = 0, \Exception $previous = null, $path = null) 36 | { 37 | $this->path = $path; 38 | 39 | parent::__construct($message, $code, $previous); 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function getPath() 46 | { 47 | return $this->path; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Exception/IOExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Exception; 16 | 17 | /** 18 | * Interface IOExceptionInterface 19 | */ 20 | interface IOExceptionInterface extends ExceptionInterface 21 | { 22 | /** 23 | * Returns the path for the exception. 24 | * 25 | * @return string The path for the exception 26 | */ 27 | public function getPath(); 28 | } 29 | -------------------------------------------------------------------------------- /Exception/RuntimeException.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Exception; 16 | 17 | /** 18 | * Class RuntimeException 19 | */ 20 | class RuntimeException extends \RuntimeException implements ExceptionInterface 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /Geolocation/City.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Geolocation; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Statistics\ViewDateTrait; 20 | use Tchoulom\ViewCounterBundle\Util\Date; 21 | 22 | /** 23 | * Class City 24 | */ 25 | class City 26 | { 27 | /** 28 | * The city name. 29 | * 30 | * @var string 31 | */ 32 | protected $name; 33 | 34 | /** 35 | * The total of views. 36 | * 37 | * @var int 38 | */ 39 | protected $total = 0; 40 | 41 | /** 42 | * The viewcounter entity. 43 | * 44 | * @var ViewCounterInterface 45 | */ 46 | protected $viewcounter; 47 | 48 | use ViewDateTrait; 49 | 50 | /** 51 | * Gets the city name. 52 | * 53 | * @return string 54 | */ 55 | public function getName(): string 56 | { 57 | return $this->name; 58 | } 59 | 60 | /** 61 | * Sets the city name. 62 | * 63 | * @param string $name 64 | * 65 | * @return self 66 | */ 67 | public function setName(string $name): self 68 | { 69 | $this->name = $name; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Gets the total of views. 76 | * 77 | * @return int 78 | */ 79 | public function getTotal(): int 80 | { 81 | return $this->total; 82 | } 83 | 84 | /** 85 | * Sets the total of views. 86 | * 87 | * @param int $total 88 | * 89 | * @return self 90 | */ 91 | public function setTotal(int $total): self 92 | { 93 | $this->total = $total; 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * Builds the city. 100 | * 101 | * @param GeolocatorAdapterInterface $geolocator The geolocator. 102 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 103 | * 104 | * @return self 105 | */ 106 | public function build(GeolocatorAdapterInterface $geolocator, ViewCounterInterface $viewcounter): self 107 | { 108 | $this->total++; 109 | $this->viewcounter = $viewcounter; 110 | $this->buildViewDate(); 111 | $this->name = $geolocator->getCity(); 112 | 113 | return $this; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Geolocation/Country.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Geolocation; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Statistics\ViewDateTrait; 20 | use Tchoulom\ViewCounterBundle\Util\Date; 21 | use Tchoulom\ViewCounterBundle\Statistics\Date as ViewDate; 22 | 23 | /** 24 | * Class Country 25 | */ 26 | class Country 27 | { 28 | /** 29 | * The region name. 30 | * 31 | * @var string 32 | */ 33 | protected $name; 34 | 35 | /** 36 | * The total of views. 37 | * 38 | * @var int 39 | */ 40 | protected $total = 0; 41 | 42 | /** 43 | * The continent name. 44 | * 45 | * @var string 46 | */ 47 | protected $continent; 48 | 49 | /** 50 | * The country regions. 51 | * 52 | * @var Region[] 53 | */ 54 | protected $regions = []; 55 | 56 | /** 57 | * The viewcounter entity. 58 | * 59 | * @var ViewCounterInterface 60 | */ 61 | protected $viewcounter; 62 | 63 | use ViewDateTrait; 64 | 65 | /** 66 | * Gets the country name. 67 | * 68 | * @return string 69 | */ 70 | public function getName(): string 71 | { 72 | return $this->name; 73 | } 74 | 75 | /** 76 | * Sets the country name. 77 | * 78 | * @param string $name 79 | * 80 | * @return self 81 | */ 82 | public function setName(string $name): self 83 | { 84 | $this->name = $name; 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * Gets the total of views. 91 | * 92 | * @return int 93 | */ 94 | public function getTotal(): int 95 | { 96 | return $this->total; 97 | } 98 | 99 | /** 100 | * Sets the total of views. 101 | * 102 | * @param int $total 103 | * 104 | * @return self 105 | */ 106 | public function setTotal(int $total): self 107 | { 108 | $this->total = $total; 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * Gets the continent name. 115 | * 116 | * @return string 117 | */ 118 | public function getContinent(): string 119 | { 120 | return $this->continent; 121 | } 122 | 123 | /** 124 | * Sets the continent name. 125 | * 126 | * @param string $continent 127 | * 128 | * @return self 129 | */ 130 | public function setContinent(string $continent): self 131 | { 132 | $this->continent = $continent; 133 | 134 | return $this; 135 | } 136 | 137 | /** 138 | * Gets the regions. 139 | * 140 | * @return Region[] 141 | */ 142 | public function getRegions(): array 143 | { 144 | return $this->regions; 145 | } 146 | 147 | /** 148 | * Builds the country. 149 | * 150 | * @param GeolocatorAdapterInterface $geolocator The geolocator. 151 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 152 | * 153 | * @return self 154 | */ 155 | public function build(GeolocatorAdapterInterface $geolocator, ViewCounterInterface $viewcounter): self 156 | { 157 | $this->total++; 158 | $this->name = $geolocator->getCountry(); 159 | $this->viewcounter = $viewcounter; 160 | $this->buildViewDate(); 161 | $this->continent = $geolocator->getContinent(); 162 | $regionName = $geolocator->getRegion(); 163 | 164 | if (isset($this->regions[$regionName])) { 165 | $region = $this->regions[$regionName]; 166 | } else { 167 | $region = new Region(); 168 | } 169 | 170 | $this->regions[$regionName] = $region->build($geolocator, $viewcounter); 171 | 172 | return $this; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /Geolocation/Region.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Geolocation; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Statistics\ViewDateTrait; 20 | use Tchoulom\ViewCounterBundle\Util\Date; 21 | 22 | /** 23 | * Class Region 24 | */ 25 | class Region 26 | { 27 | /** 28 | * The region name. 29 | * 30 | * @var string 31 | */ 32 | protected $name; 33 | 34 | /** 35 | * The total of views. 36 | * 37 | * @var int 38 | */ 39 | protected $total = 0; 40 | 41 | /** 42 | * The region cities. 43 | * 44 | * @var City[] 45 | */ 46 | protected $cities = []; 47 | 48 | /** 49 | * The viewcounter entity. 50 | * 51 | * @var ViewCounterInterface 52 | */ 53 | protected $viewcounter; 54 | 55 | use ViewDateTrait; 56 | 57 | /** 58 | * Gets the region name. 59 | * 60 | * @return string 61 | */ 62 | public function getName(): string 63 | { 64 | return $this->name; 65 | } 66 | 67 | /** 68 | * Sets the region name. 69 | * 70 | * @param string $name 71 | * 72 | * @return self 73 | */ 74 | public function setName(string $name): self 75 | { 76 | $this->name = $name; 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * Gets the total of views. 83 | * 84 | * @return int 85 | */ 86 | public function getTotal(): int 87 | { 88 | return $this->total; 89 | } 90 | 91 | /** 92 | * Sets the total of views. 93 | * 94 | * @param int $total 95 | * 96 | * @return self 97 | */ 98 | public function setTotal(int $total): self 99 | { 100 | $this->total = $total; 101 | 102 | return $this; 103 | } 104 | 105 | /** 106 | * Gets the cities. 107 | * 108 | * @return City[] 109 | */ 110 | public function getCities(): array 111 | { 112 | return $this->cities; 113 | } 114 | 115 | /** 116 | * Builds the region. 117 | * 118 | * @param GeolocatorAdapterInterface $geolocator The geolocator. 119 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 120 | * 121 | * @return self 122 | */ 123 | public function build(GeolocatorAdapterInterface $geolocator, ViewCounterInterface $viewcounter): self 124 | { 125 | $this->total++; 126 | $this->viewcounter = $viewcounter; 127 | $this->buildViewDate(); 128 | $this->name = $geolocator->getRegion(); 129 | $cityName = $geolocator->getCity(); 130 | 131 | if (isset($this->cities[$cityName])) { 132 | $city = $this->cities[$cityName]; 133 | } else { 134 | $city = new City(); 135 | } 136 | 137 | $this->cities[$cityName] = $city->build($geolocator, $viewcounter); 138 | 139 | return $this; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2018 Ernest TCHOULOM 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Manager/CounterManager.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Manager; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Repository\RepositoryInterface; 19 | 20 | 21 | /** 22 | * Class CounterManager 23 | */ 24 | class CounterManager 25 | { 26 | /** 27 | * @var RepositoryInterface 28 | */ 29 | protected $counterRepository; 30 | 31 | /** 32 | * @var RepositoryInterface 33 | */ 34 | protected $metadata; 35 | 36 | /** 37 | * CounterManager constructor. 38 | * @param RepositoryInterface $counterRepository 39 | */ 40 | public function __construct(RepositoryInterface $counterRepository) 41 | { 42 | $this->counterRepository = $counterRepository; 43 | } 44 | 45 | /** 46 | * Saves the object. 47 | * 48 | * @param $object 49 | */ 50 | public function save($object) 51 | { 52 | $this->counterRepository->save($object); 53 | } 54 | 55 | /** 56 | * Finds One By. 57 | * 58 | * @param array $criteria 59 | * @param null $orderBy 60 | * @param null $limit 61 | * @param null $offset 62 | * 63 | * @return mixed 64 | */ 65 | public function findOneBy(array $criteria, $orderBy = null, $limit = null, $offset = null) 66 | { 67 | $result = $this->counterRepository->findOneBy($criteria, $orderBy, $limit, $offset); 68 | 69 | return $result; 70 | } 71 | 72 | /** 73 | * Loads Metadata. 74 | * 75 | * @param $object 76 | * 77 | * @return $this 78 | */ 79 | public function loadMetadata($object) 80 | { 81 | $this->metadata = $this->counterRepository->loadMetadata($object); 82 | 83 | return $this; 84 | } 85 | 86 | /** 87 | * Gets the property. 88 | * 89 | * @return mixed 90 | */ 91 | public function getProperty() 92 | { 93 | return $this->counterRepository->getProperty(); 94 | } 95 | 96 | public function getMappings() 97 | { 98 | return $this->counterRepository->getMappings(); 99 | } 100 | 101 | /** 102 | * Gets the Class. 103 | * 104 | * @return mixed 105 | */ 106 | public function getClass() 107 | { 108 | return $this->counterRepository->getClass(); 109 | } 110 | 111 | /** 112 | * Cleanup the viewcounter data. 113 | * 114 | * @param \DateTimeInterface|null $min The min view date 115 | * @param \DateTimeInterface|null $max the max view date 116 | * 117 | * @return int The number of rows deleted. 118 | */ 119 | public function cleanup(\DateTimeInterface $min = null, \DateTimeInterface $max = null): int 120 | { 121 | return $this->counterRepository->cleanup($min, $max); 122 | } 123 | 124 | /** 125 | * Loads the ViewCounter data. 126 | * 127 | * @return ViewCounterInterface[] 128 | */ 129 | public function loadViewCounterData() 130 | { 131 | return $this->counterRepository->loadViewCounterData(); 132 | } 133 | 134 | /** 135 | * Sets the property. 136 | * 137 | * @param ViewCounterInterface $viewcounter 138 | * 139 | * @return ViewCounterInterface 140 | */ 141 | public function setProperty(ViewCounterInterface $viewcounter): ViewCounterInterface 142 | { 143 | $this->loadMetadata($viewcounter); 144 | 145 | foreach ($this->getMappings() as $mapping) { 146 | $property = $mapping['fieldName']; 147 | $viewcounter->setProperty($property); 148 | if ($viewcounter->getPage() !== null) { 149 | $viewcounter->setProperty($property); 150 | break; 151 | } 152 | } 153 | 154 | return $viewcounter; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Manager/StatsManager.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Manager; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Storage\StorageAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use \ReflectionException; 20 | 21 | /** 22 | * Class StatsManager is used to manage statistics. 23 | */ 24 | class StatsManager 25 | { 26 | /** 27 | * The StorageAdapter service. 28 | * 29 | * @var StorageAdapterInterface 30 | */ 31 | protected $storageAdapter; 32 | 33 | /** 34 | * Statistics constructor. 35 | * 36 | * @param StorageAdapterInterface $storageAdapter 37 | */ 38 | public function __construct(StorageAdapterInterface $storageAdapter) 39 | { 40 | $this->storageAdapter = $storageAdapter; 41 | } 42 | 43 | /** 44 | * Registers the statistics of the page. 45 | * 46 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 47 | * 48 | * @throws ReflectionException 49 | */ 50 | public function register(ViewCounterInterface $viewcounter): void 51 | { 52 | $this->storageAdapter->save($viewcounter); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Model/StatisticsNodeConfig.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Model; 16 | 17 | /** 18 | * Class StatisticsNodeConfig 19 | */ 20 | class StatisticsNodeConfig 21 | { 22 | /** 23 | * @var bool Is statistics enabled?. 24 | */ 25 | protected $isStatsEnabled; 26 | 27 | /** 28 | * @var ?string The name of the statistics file. 29 | */ 30 | protected $statsFileName; 31 | 32 | /** 33 | * @var ?string The extension of the statistics file. 34 | */ 35 | protected $statsFileExtension; 36 | 37 | /** 38 | * StatisticsNodeConfig constructor. 39 | * 40 | * @param array $statsNode 41 | */ 42 | public function __construct(array $statsNode) 43 | { 44 | $this->isStatsEnabled = $statsNode['enabled']; 45 | $this->statsFileName = $statsNode['stats_file_name']; 46 | $this->statsFileExtension = $statsNode['stats_file_extension']; 47 | } 48 | 49 | /** 50 | * Gets the enabled boolean value. 51 | * 52 | * @return bool Is stats enabled ? 53 | */ 54 | public function isStatsEnabled(): bool 55 | { 56 | return $this->isStatsEnabled; 57 | } 58 | 59 | /** 60 | * Sets the enabled value. 61 | * 62 | * @param bool $isStatsEnabled 63 | * 64 | * @return self 65 | */ 66 | public function setIsStatsEnabled(bool $isStatsEnabled): self 67 | { 68 | $this->isStatsEnabled = $isStatsEnabled; 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Gets the stats file name. 75 | * 76 | * @return string|null 77 | */ 78 | public function getStatsFileName(): ?string 79 | { 80 | return $this->statsFileName; 81 | } 82 | 83 | /** 84 | * Sets the stats file name. 85 | * 86 | * @param string $statsFileName 87 | * 88 | * @return self 89 | */ 90 | public function setStatsFileName(string $statsFileName): self 91 | { 92 | $this->statsFileName = $statsFileName; 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Gets the stats file extension. 99 | * 100 | * @return string|null 101 | */ 102 | public function getStatsFileExtension(): ?string 103 | { 104 | return $this->statsFileExtension; 105 | } 106 | 107 | /** 108 | * Sets the stats file extension. 109 | * 110 | * @param string $statsFileExtension 111 | * 112 | * @return self 113 | */ 114 | public function setStatsFileExtension(string $statsFileExtension): self 115 | { 116 | $this->statsFileExtension = $statsFileExtension; 117 | 118 | return $this; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Model/ViewCountable.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Model; 16 | 17 | /** 18 | * Interface ViewCountable 19 | */ 20 | interface ViewCountable 21 | { 22 | /** 23 | * Gets id 24 | * 25 | * @return integer 26 | */ 27 | public function getId(); 28 | 29 | /** 30 | * Get $views 31 | * 32 | * @return integer 33 | */ 34 | public function getViews(); 35 | 36 | /** 37 | * Set $views 38 | * 39 | * @param integer $views 40 | * 41 | * @return $this 42 | */ 43 | public function setViews($views); 44 | } -------------------------------------------------------------------------------- /Model/ViewcounterConfig.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Model; 16 | 17 | /** 18 | * Class ViewcounterConfig 19 | */ 20 | class ViewcounterConfig 21 | { 22 | /** 23 | * @var ViewcounterNodeConfig 24 | */ 25 | protected $viewcounterNodeConfig; 26 | 27 | /** 28 | * @var StatisticsNodeConfig 29 | */ 30 | protected $statisticsNodeConfig; 31 | 32 | /** 33 | * ViewcounterConfig constructor. 34 | * 35 | * @param ViewcounterNodeConfig $viewcounterNodeConfig 36 | * @param StatisticsNodeConfig $statisticsNodeConfig 37 | */ 38 | public function __construct(ViewcounterNodeConfig $viewcounterNodeConfig, StatisticsNodeConfig $statisticsNodeConfig) 39 | { 40 | $this->viewcounterNodeConfig = $viewcounterNodeConfig; 41 | $this->statisticsNodeConfig = $statisticsNodeConfig; 42 | } 43 | 44 | /** 45 | * Gets the viewcounter node configuration. 46 | * 47 | * @return ViewcounterNodeConfig 48 | */ 49 | public function getViewcounterNodeConfig() 50 | { 51 | return $this->viewcounterNodeConfig; 52 | } 53 | 54 | /** 55 | * Sets the viewcounter node configuration. 56 | * 57 | * @param ViewcounterNodeConfig $viewcounterNodeConfig 58 | * 59 | * @return ViewcounterConfig 60 | */ 61 | public function setViewcounterNodeConfig($viewcounterNodeConfig) 62 | { 63 | $this->viewcounterNodeConfig = $viewcounterNodeConfig; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * Gets the statistics node configuration. 70 | * 71 | * @return StatisticsNodeConfig 72 | */ 73 | public function getStatisticsNodeConfig() 74 | { 75 | return $this->statisticsNodeConfig; 76 | } 77 | 78 | /** 79 | * Sets the statistics node configuration. 80 | * 81 | * @param StatisticsNodeConfig $statisticsNodeConfig 82 | * 83 | * @return ViewcounterConfig 84 | */ 85 | public function setStatisticsNodeConfig($statisticsNodeConfig) 86 | { 87 | $this->statisticsNodeConfig = $statisticsNodeConfig; 88 | 89 | return $this; 90 | } 91 | } -------------------------------------------------------------------------------- /Model/ViewcounterNodeConfig.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Model; 16 | 17 | /** 18 | * Class ViewcounterNodeConfig 19 | */ 20 | class ViewcounterNodeConfig 21 | { 22 | /** 23 | * @var mixed The view strategy 24 | */ 25 | protected $viewStrategy; 26 | 27 | /** 28 | * ViewcounterNodeConfig constructor. 29 | * 30 | * @param array $viewcounterNode 31 | */ 32 | public function __construct(array $viewcounterNode) 33 | { 34 | $this->viewStrategy = $viewcounterNode['view_strategy']; 35 | } 36 | 37 | /** 38 | * Gets the view strategy. 39 | * 40 | * @return mixed 41 | */ 42 | public function getViewStrategy() 43 | { 44 | return $this->viewStrategy; 45 | } 46 | 47 | /** 48 | * Sets the view strategy. 49 | * 50 | * @param $viewStrategy 51 | * 52 | * @return $this 53 | */ 54 | public function setViewStrategy($viewStrategy) 55 | { 56 | $this->viewStrategy = $viewStrategy; 57 | 58 | return $this; 59 | } 60 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The View Counter Bundle 2 | ======================== 3 | 4 | Welcome to the "**TchoulomViewCounterBundle**". 5 | 6 | This bundle is used to count the number of views of web pages (the viewership). 7 | 8 | This bundle can also be used to draw a graphical representation of statistical data of the web pages. 9 | 10 | Monthly views in 2018 11 | 12 | **Table of contents** 13 | 14 | - [Features include](#features-include) 15 | - [Documentation](#documentation) 16 | - [Installation](Resources/doc/readme/installation.md#installation) 17 | - [Step 1: Download TchoulomViewCounterBundle using composer](Resources/doc/readme/installation.md#step-1-download-tchoulomviewcounterbundle-using-composer) 18 | - [Step 2: Enable the Bundle](Resources/doc/readme/installation.md#step-2-enable-the-bundle) 19 | - [Usage](Resources/doc/readme/usage-step-1-5.md#usage) 20 | - [Step 1: Interface and Property](Resources/doc/readme/usage-step-1-5.md#step-1-interface-and-property) 21 | - [Step 2: ViewCounter](Resources/doc/readme/usage-step-1-5.md#step-2-viewcounter) 22 | - [Step 3: Configuration](Resources/doc/readme/usage-step-1-5.md#step-3-configuration) 23 | - [The "view_counter"](Resources/doc/readme/usage-step-1-5.md#the-view_counter) 24 | - [The "statistics"](Resources/doc/readme/usage-step-1-5.md#the-statistics) 25 | - [Step 4: The Controller](Resources/doc/readme/usage-step-1-5.md#step-4-the-controller) 26 | - [Method 1](Resources/doc/readme/usage-step-1-5.md#method-1) 27 | - [Method 2](Resources/doc/readme/usage-step-1-5.md#method-2) 28 | - [Step 5: The View](Resources/doc/readme/usage-step-1-5.md#step-5-the-view) 29 | - [Step 6: The Geolocation](Resources/doc/readme/geolocation.md#step-6-the-geolocation) 30 | - [Step 7: Use of statistical data](Resources/doc/readme/statistics-finder.md#step-7-use-of-statistical-data) 31 | - [The *FileStatsFinder* service](Resources/doc/readme/statistics-finder.md#the-filestatsfinder-service) 32 | - [Get the *yearly* statistics](Resources/doc/readme/statistics-finder.md#get-the-yearly-statistics) 33 | - [Get the *monthly* statistics](Resources/doc/readme/statistics-finder.md#get-the-monthly-statistics) 34 | - [Get the *weekly* statistics](Resources/doc/readme/statistics-finder.md#get-the-weekly-statistics) 35 | - [Get the *daily* statistics](Resources/doc/readme/statistics-finder.md#get-the-daily-statistics) 36 | - [Get the *hourly* statistics](Resources/doc/readme/statistics-finder.md#get-the-hourly-statistics) 37 | - [Get the statistics *per minute*](Resources/doc/readme/statistics-finder.md#get-the-statistics-per-minute) 38 | - [Get the statistics *per second*](Resources/doc/readme/statistics-finder.md#get-the-statistics-per-second) 39 | - [Search for geolocation data](Resources/doc/readme/statistics-finder.md#search-for-geolocation-data) 40 | - [Build a graph with "Google Charts"](Resources/doc/readme/graph-google-charts.md#build-a-graph-with-google-charts) 41 | - [The *StatsComputer* service](Resources/doc/readme/statistics-computer.md#the-statscomputer-service) 42 | - [Calculates the *min value*](Resources/doc/readme/statistics-computer.md#calculates-the-min-value) 43 | - [Calculates the *max value*](Resources/doc/readme/statistics-computer.md#calculates-the-max-value) 44 | - [Calculates the *average*](Resources/doc/readme/statistics-computer.md#calculates-the-average) 45 | - [Calculates the *range*](Resources/doc/readme/statistics-computer.md#calculates-the-range) 46 | - [Calculates the *mode*](Resources/doc/readme/statistics-computer.md#calculates-the-mode) 47 | - [Calculates the *median*](Resources/doc/readme/statistics-computer.md#calculates-the-median) 48 | - [Count the number of values ​​in the statistical series](Resources/doc/readme/statistics-computer.md#count-the-number-of-values-in-the-statistical-series) 49 | - [Tools](Resources/doc/readme/tools-command-cleanup.md#tools) 50 | - [Command](Resources/doc/readme/tools-command-cleanup.md#command) 51 | - [Cleanup ViewCounter data](Resources/doc/readme/tools-command-cleanup.md#cleanup-viewcounter-data) 52 | - [Converts ViewCounter entities to statistical data](Resources/doc/readme/tools-command-stats-converter.md#converts-viewcounter-entities-to-statistical-data) 53 | - [Original Credits](#original-credits) 54 | - [License](#license) 55 | 56 | # Features include 57 | 58 | - Viewcounter 59 | - Statistics 60 | - Geolocation 61 | 62 | # Documentation 63 | 64 | [The ViewCounter documentation](https://github.com/tchoulom/ViewCounterBundle) 65 | 66 | # Original Credits 67 | 68 | Created by Ernest TCHOULOM 69 | 70 | # License 71 | 72 | This bundle is released under the MIT license. See the complete license in the 73 | bundle: 74 | 75 | ```text 76 | LICENSE 77 | ``` 78 | 79 | Enjoy! 80 | -------------------------------------------------------------------------------- /Repository/AbstractRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository; 16 | 17 | use Doctrine\ORM\EntityManagerInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounter as BaseViewCounter; 19 | 20 | /** 21 | * Class AbstractRepository. 22 | */ 23 | abstract class AbstractRepository implements RepositoryInterface 24 | { 25 | /** 26 | * The EntityManager 27 | * 28 | * @var EntityManagerInterface 29 | */ 30 | protected $em; 31 | 32 | /** 33 | * The metadata. 34 | */ 35 | protected $metadata; 36 | 37 | /** 38 | * AbstractPersister constructor. 39 | * 40 | * @param EntityManagerInterface $em 41 | */ 42 | public function __construct(EntityManagerInterface $em) 43 | { 44 | $this->em = $em; 45 | } 46 | 47 | /** 48 | * Saves the object. 49 | * 50 | * @param $object 51 | * 52 | * @return mixed 53 | */ 54 | abstract public function save($object); 55 | 56 | /** 57 | * Finds One By. 58 | * 59 | * @param array $criteria 60 | * @param null $orderBy 61 | * @param null $limit 62 | * @param null $offset 63 | * 64 | * @return mixed 65 | */ 66 | abstract public function findOneBy(array $criteria, $orderBy = null, $limit = null, $offset = null); 67 | 68 | /** 69 | * Gets the EntityManager. 70 | * 71 | * @return mixed 72 | */ 73 | public function getEntityManager() 74 | { 75 | return $this->em; 76 | } 77 | 78 | /** 79 | * Loads the Metadata. 80 | * 81 | * @param $object 82 | * 83 | * @return $this 84 | */ 85 | public function loadMetadata($object) 86 | { 87 | $this->metadata = $this->getEntityManager()->getClassMetadata(get_class($object)); 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * Gets the Metadata. 94 | * 95 | * @return mixed 96 | */ 97 | public function getMetadata() 98 | { 99 | return $this->metadata; 100 | } 101 | 102 | /** 103 | * Gets Mappings. 104 | * 105 | * @return mixed 106 | */ 107 | public function getMappings() 108 | { 109 | return $this->getMetadata()->getAssociationMappings(); 110 | } 111 | 112 | /** 113 | * Gets the property. 114 | * 115 | * @return mixed 116 | */ 117 | public function getProperty() 118 | { 119 | return $this->getMappings()['viewCounters']['mappedBy']; 120 | } 121 | 122 | /** 123 | * Gets the class. 124 | * 125 | * @return mixed 126 | */ 127 | public function getClass() 128 | { 129 | return $this->getMappings()['viewCounters']['targetEntity']; 130 | } 131 | 132 | /** 133 | * Gets the class Repository. 134 | * 135 | * @return mixed 136 | */ 137 | public function getClassRepository() 138 | { 139 | $class = $this->getClass(); 140 | 141 | return $this->getEntityManager()->getRepository($class); 142 | } 143 | 144 | /** 145 | * Loads the ViewCounter Class. 146 | * 147 | * @return string|null The viewcounter class 148 | */ 149 | public function loadViewCounterClass(): ?string 150 | { 151 | $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); 152 | foreach ($metadatas as $metadata) { 153 | if ($metadata->getReflectionClass()->getParentClass() instanceof \ReflectionClass 154 | && BaseViewCounter::class === $metadata->getReflectionClass()->getParentClass()->getName() 155 | ) { 156 | return $metadata->getReflectionClass()->getName(); 157 | } 158 | } 159 | 160 | return null; 161 | } 162 | 163 | /** 164 | * Loads the entity identifier. 165 | * 166 | * @param string $entityName The entity name 167 | * 168 | * @return string|null The entity identifier 169 | */ 170 | public function loadEntityIdentifier(string $entityName): ?string 171 | { 172 | $metadatas = $this->em->getMetadataFactory()->getAllMetadata(); 173 | foreach ($metadatas as $metadata) { 174 | if ($metadata->getName() === $metadata->namespace . '\\' . ucfirst($entityName)) { 175 | if (isset($metadata->getIdentifier()[0])) { 176 | return $metadata->getIdentifier()[0]; 177 | } 178 | } 179 | } 180 | 181 | return null; 182 | } 183 | } -------------------------------------------------------------------------------- /Repository/CounterRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Exception\RuntimeException; 19 | 20 | /** 21 | * Class CounterRepository 22 | */ 23 | class CounterRepository extends AbstractRepository 24 | { 25 | /** 26 | * @var string Viewcounter class not found message. 27 | */ 28 | protected const VIEWCOUNTER_CLASS_NOT_FOUND_MSG = 'No ViewCounter class to process.'; 29 | 30 | /** 31 | * Saves the object. 32 | * 33 | * @param $object 34 | * 35 | * @return mixed 36 | * @throws \Exception 37 | */ 38 | public function save($object) 39 | { 40 | try { 41 | $this->em->persist($object); 42 | $this->em->flush(); 43 | } catch (\Exception $e) { 44 | throw $e; 45 | } 46 | 47 | return $object; 48 | } 49 | 50 | /** 51 | * Finds One By. 52 | * 53 | * @param array $criteria 54 | * @param null $orderBy 55 | * @param null $limit 56 | * @param null $offset 57 | * 58 | * @return mixed 59 | */ 60 | public function findOneBy(array $criteria, $orderBy = null, $limit = null, $offset = null) 61 | { 62 | $result = $this->getClassRepository()->findOneBy($criteria, $orderBy, $limit, $offset); 63 | 64 | return $result; 65 | } 66 | 67 | /** 68 | * Cleanup the viewcounter data. 69 | * 70 | * @param \DateTimeInterface|null $min 71 | * @param \DateTimeInterface|null $max 72 | * 73 | * @return int The number of rows deleted. 74 | */ 75 | public function cleanup(\DateTimeInterface $min = null, \DateTimeInterface $max = null): int 76 | { 77 | $viewcounterClass = $this->loadViewCounterClass(); 78 | 79 | if (null == $viewcounterClass) { 80 | throw new RuntimeException(self::VIEWCOUNTER_CLASS_NOT_FOUND_MSG); 81 | } 82 | 83 | $queryBuilder = $this->em->createQueryBuilder(); 84 | $queryBuilder->delete($viewcounterClass, 'v'); 85 | $where = false; 86 | 87 | if ($min instanceof \DateTimeInterface) { 88 | $andWhere = true === $where ? 'andWhere' : 'where'; 89 | $where = true; 90 | $queryBuilder->$andWhere('v.viewDate >= :min') 91 | ->setParameter('min', $min); 92 | } 93 | if ($max instanceof \DateTimeInterface) { 94 | $andWhere = true === $where ? 'andWhere' : 'where'; 95 | $queryBuilder->$andWhere('v.viewDate <= :max') 96 | ->setParameter('max', $max); 97 | } 98 | 99 | return $queryBuilder->getQuery()->execute(); 100 | } 101 | 102 | /** 103 | * Loads the ViewCounter data. 104 | * 105 | * @return ViewCounterInterface[] 106 | */ 107 | public function loadViewCounterData() 108 | { 109 | $viewcounterClass = $this->loadViewCounterClass(); 110 | 111 | return $this->getEntityManager()->getRepository($viewcounterClass)->findAll(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Repository/DocumentRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository; 16 | 17 | 18 | /** 19 | * Interface DocumentRepositoryInterface 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository 22 | */ 23 | interface DocumentRepositoryInterface 24 | { 25 | } -------------------------------------------------------------------------------- /Repository/RepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | /** 18 | * Class CityRepository 19 | * 20 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 21 | */ 22 | class CityRepository extends MongoDBStatsRepository 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/ContinentRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | 18 | /** 19 | * Class ContinentRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class ContinentRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/CountryRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | 18 | /** 19 | * Class CountryRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class CountryRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/DayRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | /** 18 | * Class DayRepository 19 | * 20 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 21 | */ 22 | class DayRepository extends MongoDBStatsRepository 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/HourRepository.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 17 | 18 | /** 19 | * Class HourRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class HourRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/MinuteRepository.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 17 | 18 | /** 19 | * Class MinuteRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class MinuteRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/MongoDBStatsRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | use Doctrine\ODM\MongoDB\Repository\DocumentRepository; 18 | use Tchoulom\ViewCounterBundle\Repository\DocumentRepositoryInterface; 19 | 20 | /** 21 | * Class MongoDBStatsRepository 22 | * 23 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 24 | */ 25 | class MongoDBStatsRepository extends DocumentRepository implements DocumentRepositoryInterface 26 | { 27 | } 28 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/MonthRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | /** 18 | * Class MonthRepository 19 | * 20 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 21 | */ 22 | class MonthRepository extends MongoDBStatsRepository 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/PageContinentRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | 18 | /** 19 | * Class PageContinentRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class PageContinentRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/PageCountryRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | 18 | /** 19 | * Class PageCountryRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class PageCountryRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/PageRepository.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 17 | 18 | /** 19 | * Class PageRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class PageRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/RegionRepository.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 16 | 17 | /** 18 | * Class RegionRepository 19 | * 20 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 21 | */ 22 | class RegionRepository extends MongoDBStatsRepository 23 | { 24 | } 25 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/SecondRepository.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 17 | 18 | /** 19 | * Class SecondRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class SecondRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/WeekRepository.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 17 | 18 | /** 19 | * Class WeekRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class WeekRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Repository/Stats/MongoDB/YearRepository.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * (c) Ernest TCHOULOM 11 | * 12 | * For the full copyright and license information, please view the LICENSE 13 | * file that was distributed with this source code. 14 | */ 15 | 16 | namespace Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB; 17 | 18 | /** 19 | * Class YearRepository 20 | * 21 | * @package Tchoulom\ViewCounterBundle\Repository\Stats\MongoDB 22 | */ 23 | class YearRepository extends MongoDBStatsRepository 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /Resources/config/command.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tchoulom.viewcounter.command.base.class: Tchoulom\ViewCounterBundle\Command\AbstractCommand 3 | tchoulom.viewcounter.cleanup.command.class: Tchoulom\ViewCounterBundle\Command\ViewcounterCleanupCommand 4 | tchoulom.viewcounter.stats_converter.command.class: Tchoulom\ViewCounterBundle\Command\StatsConverterCommand 5 | 6 | services: 7 | 8 | # Abstract Command 9 | tchoulom.viewcounter.command.base: 10 | class: '%tchoulom.viewcounter.command.base.class%' 11 | abstract: true 12 | public: true 13 | arguments: 14 | - '@tchoulom.viewcounter.manager' 15 | - '@tchoulom.viewcounter.stats_manager' 16 | 17 | # CleanupViewcounterCommand 18 | tchoulom.viewcounter.cleanup.command: 19 | class: '%tchoulom.viewcounter.cleanup.command.class%' 20 | parent: tchoulom.viewcounter.command.base 21 | public: true 22 | tags: 23 | - { name: console.command } 24 | 25 | # StatsConverterCommand 26 | tchoulom.viewcounter.stats_converter.command: 27 | class: '%tchoulom.viewcounter.stats_converter.command.class%' 28 | parent: tchoulom.viewcounter.command.base 29 | public: true 30 | arguments: 31 | - '@tchoulom.viewcounter.stats_converter' 32 | tags: 33 | - { name: console.command } 34 | 35 | # aliases needed for services (Symfony version 4, 5) 36 | Tchoulom\ViewCounterBundle\Command\AbstractCommand: '@tchoulom.viewcounter.command.base' 37 | Tchoulom\ViewCounterBundle\Command\ViewcounterCleanupCommand: '@tchoulom.viewcounter.cleanup.command' 38 | Tchoulom\ViewCounterBundle\Command\StatsConverterCommand: '@tchoulom.viewcounter.stats_converter.command' 39 | -------------------------------------------------------------------------------- /Resources/config/geolocation.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tchoulom.viewcounter.geolocator_adapter.class: Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapter 3 | 4 | services: 5 | 6 | # GeoLocAdapter 7 | tchoulom.viewcounter.geolocator_adapter: 8 | class: '%tchoulom.viewcounter.geolocator_adapter.class%' 9 | public: true 10 | arguments: [~] 11 | 12 | # aliases needed for services (Symfony version 4, 5) 13 | Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapter: '@tchoulom.viewcounter.geolocator_adapter' 14 | -------------------------------------------------------------------------------- /Resources/config/repository.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tchoulom.viewcounter.repository.base.class: Tchoulom\ViewCounterBundle\Repository\AbstractRepository 3 | tchoulom.viewcounter.repository.class: Tchoulom\ViewCounterBundle\Repository\CounterRepository 4 | 5 | services: 6 | # ORM 7 | tchoulom.viewcounter.repository.base: 8 | class: '%tchoulom.viewcounter.repository.base.class%' 9 | abstract: true 10 | public: true 11 | arguments: 12 | - '@doctrine.orm.entity_manager' 13 | 14 | tchoulom.viewcounter.repository: 15 | class: '%tchoulom.viewcounter.repository.class%' 16 | public: true 17 | parent: tchoulom.viewcounter.repository.base 18 | 19 | # aliases needed for services (Symfony version 4, 5) 20 | Tchoulom\ViewCounterBundle\Repository\AbstractRepository: '@tchoulom.viewcounter.repository.base' 21 | Tchoulom\ViewCounterBundle\Repository\CounterRepository: '@tchoulom.viewcounter.repository' 22 | -------------------------------------------------------------------------------- /Resources/config/statistics.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tchoulom.viewcounter.stats_manager.class: Tchoulom\ViewCounterBundle\Manager\StatsManager 3 | tchoulom.viewcounter.file_stats_builder.class: Tchoulom\ViewCounterBundle\Builder\FileStatsBuilder 4 | tchoulom.viewcounter.file_stats_finder.class: Tchoulom\ViewCounterBundle\Finder\FileStatsFinder 5 | tchoulom.viewcounter.stats_computer.class: Tchoulom\ViewCounterBundle\Compute\StatsComputer 6 | tchoulom.viewcounter.stats_converter.class: Tchoulom\ViewCounterBundle\ETL\StatsConverter 7 | 8 | services: 9 | # Statistics 10 | tchoulom.viewcounter.stats_manager: 11 | class: '%tchoulom.viewcounter.stats_manager.class%' 12 | public: true 13 | arguments: 14 | - '@tchoulom.viewcounter.storage_adapter' 15 | - '@tchoulom.viewcounter.file_stats_builder' 16 | 17 | # FileStatsBuilder 18 | tchoulom.viewcounter.file_stats_builder: 19 | class: '%tchoulom.viewcounter.file_stats_builder.class%' 20 | public: true 21 | arguments: ['@tchoulom.viewcounter.geolocator_adapter'] 22 | 23 | # FileStatsFinder 24 | tchoulom.viewcounter.file_stats_finder: 25 | class: '%tchoulom.viewcounter.file_stats_finder.class%' 26 | public: true 27 | arguments: ['@tchoulom.viewcounter.filesystem_storage'] 28 | 29 | # StatsComputer 30 | tchoulom.viewcounter.stats_computer: 31 | class: '%tchoulom.viewcounter.stats_computer.class%' 32 | public: true 33 | 34 | # StatsConverter 35 | tchoulom.viewcounter.stats_converter: 36 | class: '%tchoulom.viewcounter.stats_converter.class%' 37 | public: true 38 | arguments: 39 | - '@tchoulom.viewcounter.filesystem_storage' 40 | 41 | # aliases needed for services (Symfony version 4, 5) 42 | Tchoulom\ViewCounterBundle\Manager\StatsManager: '@tchoulom.viewcounter.stats_manager' 43 | Tchoulom\ViewCounterBundle\Builder\FileStatsBuilder: '@tchoulom.viewcounter.file_stats_builder' 44 | Tchoulom\ViewCounterBundle\Finder\FileStatsFinder: '@tchoulom.viewcounter.file_stats_finder' 45 | Tchoulom\ViewCounterBundle\Compute\StatsComputer: '@tchoulom.viewcounter.stats_computer' 46 | Tchoulom\ViewCounterBundle\ETL\StatsConverter: '@tchoulom.viewcounter.stats_converter' 47 | -------------------------------------------------------------------------------- /Resources/config/storage.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tchoulom.viewcounter.storage_adapter.class: Tchoulom\ViewCounterBundle\Adapter\Storage\StorageAdapter 3 | tchoulom.viewcounter.filesystem_storage.class: Tchoulom\ViewCounterBundle\Storage\Filesystem\FilesystemStorage 4 | tchoulom.viewcounter.mongodb_storage.class: Tchoulom\ViewCounterBundle\Storage\Database\MongoDB\MongoDBStorage 5 | 6 | services: 7 | # Storage Adapter 8 | tchoulom.viewcounter.storage_adapter: 9 | class: '%tchoulom.viewcounter.storage_adapter.class%' 10 | public: true 11 | arguments: 12 | - '@tchoulom.viewcounter.filesystem_storage' 13 | 14 | # FilesystemStorage 15 | tchoulom.viewcounter.filesystem_storage: 16 | class: '%tchoulom.viewcounter.filesystem_storage.class%' 17 | public: true 18 | arguments: 19 | - '%kernel.project_dir%' 20 | - '@tchoulom.viewcounter_config' 21 | - '@tchoulom.viewcounter.file_stats_builder' 22 | 23 | # MongoDBStorage 24 | tchoulom.viewcounter.mongodb_storage: 25 | class: '%tchoulom.viewcounter.mongodb_storage.class%' 26 | public: true 27 | arguments: 28 | - ~ 29 | - '@tchoulom.viewcounter.geolocator_adapter' 30 | 31 | # aliases needed for services (Symfony version 4, 5) 32 | Tchoulom\ViewCounterBundle\Adapter\FileStorageAdapter: '@tchoulom.viewcounter.storage_adapter' 33 | Tchoulom\ViewCounterBundle\Storage\Filesystem\FilesystemStorage: '@tchoulom.viewcounter.filesystem_storage' 34 | Tchoulom\ViewCounterBundle\Storage\Database\MongoDB\MongoDBStorage: '@tchoulom.viewcounter.mongodb_storage' 35 | -------------------------------------------------------------------------------- /Resources/config/viewcounter.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | tchoulom.viewcounter.base.class: Tchoulom\ViewCounterBundle\Counter\AbstractViewCounter 3 | tchoulom.viewcounter.class: Tchoulom\ViewCounterBundle\Counter\ViewCounter 4 | tchoulom.viewcounter.manager.class: Tchoulom\ViewCounterBundle\Manager\CounterManager 5 | tchoulom.viewcounter_config.class: Tchoulom\ViewCounterBundle\Model\ViewcounterConfig 6 | tchoulom.viewcounter_node_config.class: Tchoulom\ViewCounterBundle\Model\ViewcounterNodeConfig 7 | tchoulom.statistics_node_config.class: Tchoulom\ViewCounterBundle\Model\StatisticsNodeConfig 8 | 9 | services: 10 | # Counter 11 | tchoulom.viewcounter.base: 12 | class: '%tchoulom.viewcounter.base.class%' 13 | abstract: true 14 | public: true 15 | arguments: 16 | - '@tchoulom.viewcounter.manager' 17 | - '@request_stack' 18 | - '@tchoulom.viewcounter_config' 19 | calls: 20 | - [setStatsManager, ['@tchoulom.viewcounter.stats_manager']] 21 | 22 | tchoulom.viewcounter: 23 | class: '%tchoulom.viewcounter.class%' 24 | public: true 25 | parent: tchoulom.viewcounter.base 26 | 27 | # Manager 28 | tchoulom.viewcounter.manager: 29 | class: '%tchoulom.viewcounter.manager.class%' 30 | public: true 31 | arguments: 32 | - '@tchoulom.viewcounter.repository' 33 | 34 | # Viewcounter configuration 35 | tchoulom.viewcounter_config: 36 | class: '%tchoulom.viewcounter_config.class%' 37 | public: true 38 | arguments: 39 | - '@tchoulom.viewcounter_node_config' 40 | - '@tchoulom.statistics_node_config' 41 | 42 | # Viewcounter node configuration 43 | tchoulom.viewcounter_node_config: 44 | class: '%tchoulom.viewcounter_node_config.class%' 45 | public: true 46 | arguments: [~] 47 | 48 | # Statistics node configuration 49 | tchoulom.statistics_node_config: 50 | class: '%tchoulom.statistics_node_config.class%' 51 | public: true 52 | arguments: [~] 53 | 54 | # aliases needed for services (Symfony version 4, 5) 55 | Tchoulom\ViewCounterBundle\Counter\AbstractViewCounter: '@tchoulom.viewcounter.base' 56 | Tchoulom\ViewCounterBundle\Counter\ViewCounter: '@tchoulom.viewcounter' 57 | Tchoulom\ViewCounterBundle\Manager\CounterManager: '@tchoulom.viewcounter.manager' 58 | Tchoulom\ViewCounterBundle\Model\ViewcounterConfig: '@tchoulom.viewcounter_config' 59 | Tchoulom\ViewCounterBundle\Model\ViewcounterNodeConfig: '@tchoulom.viewcounter_node_config' 60 | Tchoulom\ViewCounterBundle\Model\StatisticsNodeConfig: '@tchoulom.statistics_node_config' 61 | -------------------------------------------------------------------------------- /Resources/doc/images/geolocation-data-washington.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tchoulom/ViewCounterBundle/3d8686988c4976de5f2e887aa7fa6c1f920297a7/Resources/doc/images/geolocation-data-washington.png -------------------------------------------------------------------------------- /Resources/doc/images/geolocation-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tchoulom/ViewCounterBundle/3d8686988c4976de5f2e887aa7fa6c1f920297a7/Resources/doc/images/geolocation-data.png -------------------------------------------------------------------------------- /Resources/doc/images/geolocation-view-date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tchoulom/ViewCounterBundle/3d8686988c4976de5f2e887aa7fa6c1f920297a7/Resources/doc/images/geolocation-view-date.png -------------------------------------------------------------------------------- /Resources/doc/images/monthly-views-2018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tchoulom/ViewCounterBundle/3d8686988c4976de5f2e887aa7fa6c1f920297a7/Resources/doc/images/monthly-views-2018.png -------------------------------------------------------------------------------- /Resources/doc/images/statistical-data-2018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tchoulom/ViewCounterBundle/3d8686988c4976de5f2e887aa7fa6c1f920297a7/Resources/doc/images/statistical-data-2018.png -------------------------------------------------------------------------------- /Resources/doc/images/statistical-data-first-week-january-2018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tchoulom/ViewCounterBundle/3d8686988c4976de5f2e887aa7fa6c1f920297a7/Resources/doc/images/statistical-data-first-week-january-2018.png -------------------------------------------------------------------------------- /Resources/doc/readme/geolocation.md: -------------------------------------------------------------------------------- 1 | ## Step 6: The Geolocation 2 | 3 | Some bundles can be used to have a geolocation system in your project. 4 | These bundles usually use the ip address in order to geolocate the visitor of the web page. 5 | 6 | For the purposes of this documentation, we will use this bundle, for example: 7 | 8 | **gpslab/geoip2** : [https://github.com/gpslab/geoip2](https://github.com/gpslab/geoip2) 9 | 10 | You can read the documentation for installing and using this bundle if you want to use it. 11 | 12 | Otherwise, you can use another geolocation bundle according to your preferences. 13 | 14 | *****Create the "Geolocator" service that will allow you to manage geolocation data***** 15 | 16 | ```php 17 | request = $requestStack->getCurrentRequest(); 52 | $this->reader = $reader; 53 | } 54 | 55 | /** 56 | * Gets the record. 57 | * 58 | * @return \GeoIp2\Model\City|mixed 59 | * @throws \GeoIp2\Exception\AddressNotFoundException 60 | * @throws \MaxMind\Db\Reader\InvalidDatabaseException 61 | */ 62 | public function getRecord() 63 | { 64 | $clientIp = $this->request->getClientIp(); 65 | 66 | return $this->reader->city($clientIp); 67 | } 68 | 69 | /** 70 | * Gets the continent. 71 | * 72 | * @return string 73 | * @throws \GeoIp2\Exception\AddressNotFoundException 74 | * @throws \MaxMind\Db\Reader\InvalidDatabaseException 75 | */ 76 | public function getContinent(): string 77 | { 78 | return $this->getRecord()->continent->name; 79 | } 80 | 81 | /** 82 | * Gets the country. 83 | * 84 | * @return string 85 | * @throws \GeoIp2\Exception\AddressNotFoundException 86 | * @throws \MaxMind\Db\Reader\InvalidDatabaseException 87 | */ 88 | public function getCountry(): string 89 | { 90 | return $this->getRecord()->country->name; 91 | } 92 | 93 | /** 94 | * Gets the region. 95 | * 96 | * @return string 97 | * @throws \GeoIp2\Exception\AddressNotFoundException 98 | * @throws \MaxMind\Db\Reader\InvalidDatabaseException 99 | */ 100 | public function getRegion(): string 101 | { 102 | return $this->getRecord()->subdivisions[0]->names['en']; 103 | } 104 | 105 | /** 106 | * Gets the city. 107 | * 108 | * @return string 109 | * @throws \GeoIp2\Exception\AddressNotFoundException 110 | * @throws \MaxMind\Db\Reader\InvalidDatabaseException 111 | */ 112 | public function getCity(): string 113 | { 114 | return $this->getRecord()->city->name; 115 | } 116 | } 117 | ``` 118 | 119 | Your Geolocation service must implement the "Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface" interface. 120 | 121 | you are free to improve the above "Geolocator" service, in particular to verify the existence of geolocation data. 122 | 123 | You can go to this step for the use of geolocation data [Search for geolocation data](statistics-finder.md#search-for-geolocation-data). 124 | -------------------------------------------------------------------------------- /Resources/doc/readme/graph-google-charts.md: -------------------------------------------------------------------------------- 1 | ### Build a graph with "Google Charts" 2 | 3 | You can now use these statistical data to build a graph, as shown in the following figure: 4 | 5 | **Statistics of monthly views in 2018** 6 | 7 | Monthly views in 2018 8 | 9 | Also, you can build the graph on statistics of **daily view**, **hourly view**, **weekly view** and **yearly view** according to the data in the statistics file. 10 | 11 | You can find out about "Google Charts" [here](https://developers.google.com/chart/interactive/docs/gallery/linechart) 12 | -------------------------------------------------------------------------------- /Resources/doc/readme/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Step 1: Download TchoulomViewCounterBundle using composer 4 | 5 | You can install it via Composer: 6 | 7 | ``` bash 8 | $ php composer.phar update tchoulom/view-counter-bundle 9 | ``` 10 | or 11 | ``` bash 12 | $ composer require tchoulom/view-counter-bundle 13 | ``` 14 | or 15 | ``` bash 16 | $ composer req tchoulom/view-counter-bundle 17 | ``` 18 | 19 | Check that it is recorded in the **composer.json** file 20 | 21 | ```js 22 | { 23 | "require": { 24 | ... 25 | "tchoulom/view-counter-bundle": "^5.0" 26 | ... 27 | } 28 | } 29 | ``` 30 | ## Step 2: Enable the Bundle 31 | 32 | Edit the **appKernel.php** file 33 | 34 | ```php 35 | ... 36 | $bundles = array( 37 | ... 38 | new Tchoulom\ViewCounterBundle\TchoulomViewCounterBundle(), 39 | ... 40 | ); 41 | ... 42 | ``` -------------------------------------------------------------------------------- /Resources/doc/readme/statistics-computer.md: -------------------------------------------------------------------------------- 1 | ### The *StatsComputer* service 2 | 3 | Use the **StatsComputer** service to calculate the min value, max value, average value, range value, mode value, median value and the number of occurrences of the statistics : 4 | 5 | First of all, get the stats computer service 6 | 7 | ```php 8 | $statsComputer = $this->get('tchoulom.viewcounter.stats_computer'); 9 | ``` 10 | 11 | The functions of the **statsComputer** service can take as argument the *$yearlyStats*, *$monthlyStats*, *$weeklyStats*, *$daylyStats*, *$hourlyStats*, *$statsPerMinute*, and *$statsPerSecond* 12 | 13 | #### Calculates the *min value* 14 | 15 | ```php 16 | // Get the min value of the yearly statistics 17 | $minValue = $statsComputer->computeMinValue($yearlyStats); 18 | ``` 19 | 20 | Result: 21 | ```php 22 | [2017,47882376] 23 | ``` 24 | 25 | #### Calculates the *max value* 26 | 27 | ```php 28 | // Get the max value of the monthly statistics 29 | $maxValue = $statsComputer->computeMaxValue($monthlyStats); 30 | ``` 31 | 32 | Result: 33 | ```php 34 | [8,951224] 35 | ``` 36 | 37 | #### Calculates the *average* 38 | 39 | The **average** is the sum of the values ​​of the statistical series divided by the number of values. 40 | 41 | ```php 42 | // Get the average of the weekly statistics 43 | $average = $statsComputer->computeAverage($weeklyStats); 44 | ``` 45 | 46 | Result: 47 | ```php 48 | 265039 49 | ``` 50 | 51 | #### Calculates the *range* 52 | 53 | The **range** is the difference between the highest number and the lowest number. 54 | 55 | ```php 56 | // Get the range of the daily statistics 57 | $range = $statsComputer->computeRange($dailyStats); 58 | ``` 59 | 60 | Result: 61 | ```php 62 | 6 63 | ``` 64 | 65 | #### Calculates the *mode* 66 | 67 | The **mode** is the number that is in the array the most times. 68 | 69 | ```php 70 | // Get the mode of the hourly statistics 71 | $mode = $statsComputer->computeMode($hourlyStats); 72 | ``` 73 | 74 | Result: 75 | ```php 76 | 700 77 | ``` 78 | 79 | #### Calculates the *median* 80 | 81 | The **median** is the middle value after the numbers are sorted smallest to largest. 82 | 83 | ```php 84 | // Get the median of the statistics per minute 85 | $median = $statsComputer->computeMedian($statsPerMinute); 86 | ``` 87 | 88 | Result: 89 | ```php 90 | 75.5 91 | ``` 92 | 93 | #### Count the number of values ​​in the statistical series 94 | 95 | ```php 96 | // Get the count of the statistics per second 97 | $count = $statsComputer->count($statsPerSecond); 98 | ``` 99 | 100 | Result: 101 | ```php 102 | 60 103 | ``` 104 | -------------------------------------------------------------------------------- /Resources/doc/readme/tools-command-cleanup.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | ## Command 4 | 5 | ### Cleanup viewcounter data 6 | 7 | You can delete the viewcounter data using the **ViewcounterCleanupCommand** command: 8 | 9 | - Delete all the viewcounter data from the database: 10 | 11 | ```bash 12 | php bin/console tchoulom:viewcounter:cleanup 13 | ``` 14 | 15 | - Delete all the viewcounter data whose article was viewed at least 1 hour ago: 16 | 17 | ```bash 18 | php bin/console tchoulom:viewcounter:cleanup --min=1h 19 | ``` 20 | 21 | - Delete all the viewcounter data whose article was viewed at most 1 day ago: 22 | 23 | ```bash 24 | php bin/console tchoulom:viewcounter:cleanup --max=1d 25 | ``` 26 | 27 | - Delete all the viewcounter data whose article was viewed at least 3 years ago: 28 | 29 | ```bash 30 | php bin/console tchoulom:viewcounter:cleanup --min=3y 31 | ``` 32 | 33 | - Delete all the viewcounter data whose article was viewed at most 5 months ago: 34 | 35 | ```bash 36 | php bin/console tchoulom:viewcounter:cleanup --max=5M 37 | ``` 38 | 39 | - Add the 'auto-approve' option to skip approval questions: 40 | 41 | ```bash 42 | php bin/console tchoulom:viewcounter:cleanup --max=5M --auto-approve=true 43 | 44 | By default, the value of the 'auto-approve' option is equal to false. 45 | ``` 46 | 47 | - Examples of date interval: 48 | 49 | ```text 50 | 's' => 'second' 51 | 'm' => 'minute' 52 | 'h' => 'hour' 53 | 'd' => 'day' 54 | 'w' => 'week' 55 | 'M' => 'month' 56 | 'y' => 'year' 57 | ``` 58 | -------------------------------------------------------------------------------- /Resources/doc/readme/tools-command-stats-converter.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | ## Command 4 | 5 | ### Converts ViewCounter entities to statistical data 6 | 7 | The creation of statistical data after each view count may slow performance of your application. 8 | 9 | It is possible to avoid the creation of statistical data after each view count, by proceeding as follows: 10 | 11 | - Disable the use of statistics 12 | 13 | Set **enabled** to **false** in config : 14 | 15 | ```yaml 16 | 17 | tchoulom_view_counter: 18 | ... 19 | statistics: 20 | enabled: false 21 | ... 22 | ``` 23 | 24 | - Run the following command: 25 | 26 | This command converts ViewCounter entities to statistical data. 27 | 28 | ```bash 29 | php bin/console tchoulom:viewcounter:stats:convert 30 | ``` 31 | 32 | or 33 | 34 | ```bash 35 | php bin/console tchoulom:viewcounter:stats:convert --cleanup=true 36 | ``` 37 | 38 | - Add the 'auto-approve' option to skip approval questions: 39 | 40 | ```bash 41 | php bin/console tchoulom:viewcounter:stats:convert --cleanup=true --auto-approve=true 42 | 43 | By default, the value of the 'auto-approve' option is equal to false. 44 | ``` 45 | 46 | This command can be automated via a cron task. 47 | 48 | The **cleanup** option allows to delete or not the ViewCounter entities after the generation of the statistical data. 49 | 50 | If the **cleanup** option is equal to **true**, the ViewCounter entities will be deleted after generating the statistical data. 51 | 52 | If the **cleanup** option is equal to **false**, the ViewCounter entities will not be deleted after generating the statistical data. 53 | 54 | By default the value of the **cleanup** option is equal to **true**. 55 | -------------------------------------------------------------------------------- /Statistics/Date.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | /** 18 | * Class Date 19 | */ 20 | class Date 21 | { 22 | /** 23 | * The total. 24 | * 25 | * @var int 26 | */ 27 | protected $total = 0; 28 | 29 | /** 30 | * The Full Date. 31 | * 32 | * @var \DateTimeInterface 33 | */ 34 | protected $fullDate; 35 | 36 | /** 37 | * Date constructor. 38 | * 39 | * @param int $total 40 | * @param $fullDate 41 | */ 42 | public function __construct(int $total, $fullDate) 43 | { 44 | $this->total = $total; 45 | $this->fullDate = $fullDate; 46 | } 47 | 48 | /** 49 | * Gets the total. 50 | * 51 | * @return int The total 52 | */ 53 | public function getTotal(): int 54 | { 55 | return $this->total; 56 | } 57 | 58 | /** 59 | * Sets the total. 60 | * 61 | * @param int $total The total 62 | * 63 | * @return self 64 | */ 65 | public function setTotal(int $total): self 66 | { 67 | $this->total = $total; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Gets the full date. 74 | * 75 | * @return \DateTimeInterface The DateTimeInterface 76 | */ 77 | public function getFullDate(): \DateTimeInterface 78 | { 79 | return $this->fullDate; 80 | } 81 | 82 | /** 83 | * Sets the full date. 84 | * 85 | * @param \DateTimeInterface $fullDate The DateTimeInterface 86 | * 87 | * @return self 88 | */ 89 | public function setFullDate(\DateTimeInterface $fullDate): self 90 | { 91 | $this->fullDate = $fullDate; 92 | 93 | return $this; 94 | } 95 | 96 | /** 97 | * Builds the Date. 98 | * 99 | * @return self 100 | */ 101 | public function build(): self 102 | { 103 | $this->total++; 104 | 105 | return $this; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Statistics/Day.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Util\Date; 19 | 20 | /** 21 | * Class Day 22 | */ 23 | class Day 24 | { 25 | /** 26 | * The Day name. 27 | * 28 | * @var string 29 | */ 30 | protected $name; 31 | 32 | /** 33 | * The total. 34 | * 35 | * @var int 36 | */ 37 | protected $total = 0; 38 | 39 | /** 40 | * The Date. 41 | * 42 | * @var \DateTimeInterface 43 | */ 44 | protected $date; 45 | 46 | use HourTrait; 47 | 48 | /** 49 | * Day constructor. 50 | * 51 | * @param string $name 52 | * @param int $total 53 | */ 54 | public function __construct(string $name, int $total) 55 | { 56 | $this->name = $name; 57 | $this->total = $total; 58 | } 59 | 60 | /** 61 | * Gets the name. 62 | * 63 | * @return string 64 | */ 65 | public function getName(): string 66 | { 67 | return $this->name; 68 | } 69 | 70 | /** 71 | * Sets the name. 72 | * 73 | * @param string $name 74 | * 75 | * @return self 76 | */ 77 | public function setName(string $name): self 78 | { 79 | $this->name = $name; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * Gets the date. 86 | * 87 | * @return \DateTimeInterface 88 | */ 89 | public function getDate(): \DateTimeInterface 90 | { 91 | return $this->date; 92 | } 93 | 94 | /** 95 | * Sets the date. 96 | * 97 | * @param \DateTimeInterface $date 98 | * 99 | * @return self 100 | */ 101 | public function setDate(\DateTimeInterface $date): self 102 | { 103 | $this->date = $date; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * Gets the total. 110 | * 111 | * @return int 112 | */ 113 | public function getTotal(): int 114 | { 115 | return $this->total; 116 | } 117 | 118 | /** 119 | * Sets the total. 120 | * 121 | * @param int $total 122 | * 123 | * @return self 124 | */ 125 | public function setTotal(int $total): self 126 | { 127 | $this->total = $total; 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * Builds the day. 134 | * 135 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 136 | * 137 | * @return self 138 | * 139 | * @throws \Exception 140 | */ 141 | public function build(ViewCounterInterface $viewcounter): self 142 | { 143 | $this->total++; 144 | $this->date = $viewcounter->getViewDate(); 145 | $hourName = 'h' . $viewcounter->getViewDate()->format('H'); 146 | $hour = $this->getHour($hourName); 147 | $hourName = strtolower($hour->getName()); 148 | $this->$hourName = $hour->build($viewcounter); 149 | 150 | return $this; 151 | } 152 | 153 | /** 154 | * Gets the hour. 155 | * 156 | * @param string|null $hourName The hour name. 157 | * 158 | * @return Hour The hour. 159 | */ 160 | public function getHour(string $hourName = null): Hour 161 | { 162 | if (null == $hourName) { 163 | $hourName = 'h' . Date::getHour(); 164 | } 165 | 166 | $hour = $this->get($hourName); 167 | if (!$hour instanceof Hour) { 168 | $hour = new Hour($hourName, 0); 169 | } 170 | 171 | return $hour; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Statistics/Hour.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Util\Date; 19 | 20 | /** 21 | * Class Hour 22 | */ 23 | class Hour 24 | { 25 | /** 26 | * The Hour name. 27 | * 28 | * @var string 29 | */ 30 | protected $name; 31 | 32 | /** 33 | * The Full Hour. 34 | * 35 | * @var false|string 36 | */ 37 | protected $fullHour; 38 | 39 | /** 40 | * The total. 41 | * 42 | * @var int 43 | */ 44 | protected $total = 0; 45 | 46 | use MinuteTrait; 47 | 48 | /** 49 | * Hour constructor. 50 | * 51 | * @param string $name 52 | * @param int $total 53 | */ 54 | public function __construct(string $name, int $total) 55 | { 56 | $this->name = $name; 57 | $this->total = $total; 58 | } 59 | 60 | /** 61 | * Gets the name. 62 | * 63 | * @return string 64 | */ 65 | public function getName(): string 66 | { 67 | return $this->name; 68 | } 69 | 70 | /** 71 | * Sets the name. 72 | * 73 | * @param string $name 74 | * 75 | * @return self 76 | */ 77 | public function setName(string $name): self 78 | { 79 | $this->name = $name; 80 | 81 | return $this; 82 | } 83 | 84 | /** 85 | * Gets the full hour. 86 | * 87 | * @return false|string 88 | */ 89 | public function getFullHour() 90 | { 91 | return $this->fullHour; 92 | } 93 | 94 | /** 95 | * Sets the full hour. 96 | * 97 | * @param false|string $fullHour 98 | * 99 | * @return self 100 | */ 101 | public function setFullHour($fullHour): self 102 | { 103 | $this->fullHour = $fullHour; 104 | 105 | return $this; 106 | } 107 | 108 | 109 | /** 110 | * Gets the total. 111 | * 112 | * @return int 113 | */ 114 | public function getTotal(): int 115 | { 116 | return $this->total; 117 | } 118 | 119 | /** 120 | * Sets the total. 121 | * 122 | * @param $total 123 | * 124 | * @return self 125 | */ 126 | public function setTotal(int $total): self 127 | { 128 | $this->total = $total; 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Builds the hour. 135 | * 136 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 137 | * 138 | * @return self 139 | */ 140 | public function build(ViewCounterInterface $viewcounter): self 141 | { 142 | $this->total++; 143 | $this->fullHour = Date::getFullHour(); 144 | 145 | $minuteName = 'm' . $viewcounter->getViewDate()->format('i'); 146 | $minute = $this->getMinute($minuteName); 147 | $minuteName = strtolower($minute->getName()); 148 | $this->$minuteName = $minute->build($viewcounter); 149 | 150 | return $this; 151 | } 152 | 153 | /** 154 | * Gets the minute. 155 | * 156 | * @param string|null $minuteName The minute name. 157 | * 158 | * @return Minute The minute. 159 | */ 160 | public function getMinute(string $minuteName = null): Minute 161 | { 162 | if (null == $minuteName) { 163 | $minuteName = 'm' . Date::getMinute(); 164 | } 165 | 166 | $minute = $this->get($minuteName); 167 | if (!$minute instanceof Minute) { 168 | $minute = new Minute($minuteName, 0); 169 | } 170 | 171 | return $minute; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Statistics/HourTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | /** 18 | * Trait HourTrait 19 | */ 20 | trait HourTrait 21 | { 22 | protected $h00; 23 | protected $h01; 24 | protected $h02; 25 | protected $h03; 26 | protected $h04; 27 | protected $h05; 28 | protected $h06; 29 | protected $h07; 30 | protected $h08; 31 | protected $h09; 32 | protected $h10; 33 | protected $h11; 34 | protected $h12; 35 | protected $h13; 36 | protected $h14; 37 | protected $h15; 38 | protected $h16; 39 | protected $h17; 40 | protected $h18; 41 | protected $h19; 42 | protected $h20; 43 | protected $h21; 44 | protected $h22; 45 | protected $h23; 46 | 47 | /** 48 | * Gets the hour. 49 | * 50 | * @param string $hourName The given hour name. 51 | * 52 | * @return Hour|null The hour. 53 | */ 54 | public function get(string $hourName): ?Hour 55 | { 56 | return $this->$hourName; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Statistics/Minute.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Util\Date; 19 | 20 | /** 21 | * Class Minute 22 | */ 23 | class Minute 24 | { 25 | /** 26 | * The name. 27 | * 28 | * @var string 29 | */ 30 | protected $name; 31 | 32 | /** 33 | * The total. 34 | * 35 | * @var int 36 | */ 37 | protected $total = 0; 38 | 39 | use SecondTrait; 40 | 41 | /** 42 | * Minute constructor. 43 | * 44 | * @param string $name 45 | * @param int $total 46 | */ 47 | public function __construct(string $name, int $total) 48 | { 49 | $this->name = $name; 50 | $this->total = $total; 51 | } 52 | 53 | /** 54 | * Gets the name. 55 | * 56 | * @return string 57 | */ 58 | public function getName(): string 59 | { 60 | return $this->name; 61 | } 62 | 63 | /** 64 | * Sets the name. 65 | * 66 | * @param string $name 67 | * 68 | * @return self 69 | */ 70 | public function setName(string $name): self 71 | { 72 | $this->name = $name; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Gets the total. 79 | * 80 | * @return int 81 | */ 82 | public function getTotal(): int 83 | { 84 | return $this->total; 85 | } 86 | 87 | /** 88 | * Sets the total. 89 | * 90 | * @param int $total 91 | * 92 | * @return self 93 | */ 94 | public function setTotal(int $total): self 95 | { 96 | $this->total = $total; 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Builds the minute. 103 | * 104 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 105 | * 106 | * @return self 107 | */ 108 | public function build(ViewCounterInterface $viewcounter): self 109 | { 110 | $this->total++; 111 | 112 | $secondName = 's' . $viewcounter->getViewDate()->format('s'); 113 | $second = $this->getSecond($secondName); 114 | $secondName = strtolower($second->getName()); 115 | $this->$secondName = $second->build($viewcounter); 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * Gets the second. 122 | * 123 | * @param string|null $secondName The second name. 124 | * 125 | * @return Second The second. 126 | */ 127 | public function getSecond(string $secondName = null): Second 128 | { 129 | if (null == $secondName) { 130 | $secondName = 's' . Date::getSecond(); 131 | } 132 | 133 | $second = $this->get($secondName); 134 | if (!$second instanceof Second) { 135 | $second = new Second($secondName, 0); 136 | } 137 | 138 | return $second; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Statistics/MinuteTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | /** 18 | * Trait MinuteTrait 19 | */ 20 | trait MinuteTrait 21 | { 22 | protected $m00; 23 | protected $m01; 24 | protected $m02; 25 | protected $m03; 26 | protected $m04; 27 | protected $m05; 28 | protected $m06; 29 | protected $m07; 30 | protected $m08; 31 | protected $m09; 32 | protected $m10; 33 | protected $m11; 34 | protected $m12; 35 | protected $m13; 36 | protected $m14; 37 | protected $m15; 38 | protected $m16; 39 | protected $m17; 40 | protected $m18; 41 | protected $m19; 42 | protected $m20; 43 | protected $m21; 44 | protected $m22; 45 | protected $m23; 46 | protected $m24; 47 | protected $m25; 48 | protected $m26; 49 | protected $m27; 50 | protected $m28; 51 | protected $m29; 52 | protected $m30; 53 | protected $m31; 54 | protected $m32; 55 | protected $m33; 56 | protected $m34; 57 | protected $m35; 58 | protected $m36; 59 | protected $m37; 60 | protected $m38; 61 | protected $m39; 62 | protected $m40; 63 | protected $m41; 64 | protected $m42; 65 | protected $m43; 66 | protected $m44; 67 | protected $m45; 68 | protected $m46; 69 | protected $m47; 70 | protected $m48; 71 | protected $m49; 72 | protected $m50; 73 | protected $m51; 74 | protected $m52; 75 | protected $m53; 76 | protected $m54; 77 | protected $m55; 78 | protected $m56; 79 | protected $m57; 80 | protected $m58; 81 | protected $m59; 82 | 83 | /** 84 | * Gets the minute. 85 | * 86 | * @param string $minuteName The minute name. 87 | * 88 | * @return Minute|null The minute. 89 | */ 90 | public function get(string $minuteName): ?Minute 91 | { 92 | return $this->$minuteName; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Statistics/Month.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Util\Date; 19 | 20 | /** 21 | * Class Month 22 | */ 23 | class Month 24 | { 25 | /** 26 | * The month number. 27 | * 28 | * @var int 29 | */ 30 | protected $monthNumber; 31 | 32 | /** 33 | * The total. 34 | * 35 | * @var int 36 | */ 37 | protected $total = 0; 38 | 39 | /** 40 | * The weeks. 41 | * 42 | * @var Week[] 43 | */ 44 | protected $weeks = []; 45 | 46 | /** 47 | * Month constructor. 48 | */ 49 | public function __construct() 50 | { 51 | $this->monthNumber = Date::getNowMonth(); 52 | } 53 | 54 | /** 55 | * Gets the number of month. 56 | * 57 | * @return int 58 | */ 59 | public function getMonthNumber(): int 60 | { 61 | return $this->monthNumber; 62 | } 63 | 64 | /** 65 | * Sets the number of month. 66 | * 67 | * @param int $monthNumber 68 | * 69 | * @return self 70 | */ 71 | public function setMonthNumber(int $monthNumber): self 72 | { 73 | $this->monthNumber = $monthNumber; 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * Gets the total. 80 | * 81 | * @return int 82 | */ 83 | public function getTotal(): int 84 | { 85 | return $this->total; 86 | } 87 | 88 | /** 89 | * Sets the total. 90 | * 91 | * @param int $total 92 | * 93 | * @return self 94 | */ 95 | public function setTotal(int $total): self 96 | { 97 | $this->total = $total; 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | * Gets the weeks. 104 | * 105 | * @return Week[] 106 | */ 107 | public function getWeeks(): array 108 | { 109 | return $this->weeks; 110 | } 111 | 112 | /** 113 | * Builds the week. 114 | * 115 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 116 | * 117 | * @return self 118 | */ 119 | public function buildWeek(ViewCounterInterface $viewcounter): self 120 | { 121 | $this->total++; 122 | $weekNumber = intval($viewcounter->getViewDate()->format('W')); 123 | 124 | if (isset($this->weeks[$weekNumber])) { 125 | $week = $this->weeks[$weekNumber]; 126 | } else { 127 | $week = new Week(); 128 | } 129 | 130 | $this->weeks[$weekNumber] = $week->buildDay($viewcounter); 131 | 132 | return $this; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Statistics/Page.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Adapter\Geolocator\GeolocatorAdapterInterface; 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Geolocation\Country; 20 | use Tchoulom\ViewCounterBundle\Util\Date; 21 | 22 | /** 23 | * Class Page 24 | */ 25 | class Page 26 | { 27 | /** 28 | * The page ID. 29 | * 30 | * @var int 31 | */ 32 | protected $id; 33 | 34 | /** 35 | * The total of views of the current page. 36 | * 37 | * @var int 38 | */ 39 | protected $total = 0; 40 | 41 | /** 42 | * The years. 43 | * 44 | * @var Year[] 45 | */ 46 | protected $years = []; 47 | 48 | /** 49 | * The countries. 50 | * 51 | * @var Country[] 52 | */ 53 | protected $countries = []; 54 | 55 | /** 56 | * Page constructor. 57 | * 58 | * @param int $id 59 | */ 60 | public function __construct(int $id) 61 | { 62 | $this->id = $id; 63 | } 64 | 65 | /** 66 | * Gets the Id. 67 | * 68 | * @return int 69 | */ 70 | public function getId(): int 71 | { 72 | return $this->id; 73 | } 74 | 75 | /** 76 | * Gets the total of views. 77 | * 78 | * @return int 79 | */ 80 | public function getTotal(): int 81 | { 82 | return $this->total; 83 | } 84 | 85 | /** 86 | * Sets the total of views. 87 | * 88 | * @param int $total 89 | * 90 | * @return self 91 | */ 92 | public function setTotal(int $total): self 93 | { 94 | $this->total = $total; 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * @return Year[] 101 | */ 102 | public function getYears(): array 103 | { 104 | return $this->years; 105 | } 106 | 107 | /** 108 | * Gets the countries. 109 | * 110 | * @return Country[] 111 | */ 112 | public function getCountries(): array 113 | { 114 | return $this->countries; 115 | } 116 | 117 | /** 118 | * Builds the year. 119 | * 120 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 121 | * 122 | * @return self 123 | */ 124 | public function buildYear(ViewCounterInterface $viewcounter): self 125 | { 126 | $this->total++; 127 | $yearNumber = intval($viewcounter->getViewDate()->format('Y')); 128 | 129 | if (isset($this->years[$yearNumber])) { 130 | $year = $this->years[$yearNumber]; 131 | } else { 132 | $year = new Year(); 133 | } 134 | 135 | $this->years[$yearNumber] = $year->buildMonth($viewcounter); 136 | 137 | return $this; 138 | } 139 | 140 | /** 141 | * Builds the country. 142 | * 143 | * @param GeolocatorAdapterInterface $geolocator The geolocator. 144 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 145 | * 146 | * @return self 147 | */ 148 | public function buildCountry(GeolocatorAdapterInterface $geolocator, ViewCounterInterface $viewcounter): self 149 | { 150 | $countryName = $geolocator->getCountry(); 151 | 152 | if (isset($this->countries[$countryName])) { 153 | $country = $this->countries[$countryName]; 154 | } else { 155 | $country = new Country(); 156 | } 157 | 158 | $this->countries[$countryName] = $country->build($geolocator, $viewcounter); 159 | 160 | return $this; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /Statistics/Second.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | 19 | /** 20 | * Class Second 21 | */ 22 | class Second 23 | { 24 | /** 25 | * The second name. 26 | * 27 | * @var string 28 | */ 29 | protected $name; 30 | 31 | /** 32 | * The total. 33 | * 34 | * @var int 35 | */ 36 | protected $total = 0; 37 | 38 | /** 39 | * Second constructor. 40 | * 41 | * @param string $name 42 | * @param int $total 43 | */ 44 | public function __construct(string $name, int $total) 45 | { 46 | $this->name = $name; 47 | $this->total = $total; 48 | } 49 | 50 | /** 51 | * Gets the name. 52 | * 53 | * @return string 54 | */ 55 | public function getName(): string 56 | { 57 | return $this->name; 58 | } 59 | 60 | /** 61 | * Sets the name. 62 | * 63 | * @param string $name 64 | * 65 | * @return self 66 | */ 67 | public function setName(string $name): self 68 | { 69 | $this->name = $name; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Gets the total. 76 | * 77 | * @return int 78 | */ 79 | public function getTotal(): int 80 | { 81 | return $this->total; 82 | } 83 | 84 | /** 85 | * Sets the total. 86 | * 87 | * @param int $total 88 | * 89 | * @return self 90 | */ 91 | public function setTotal(int $total): self 92 | { 93 | $this->total = $total; 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * Builds the second. 100 | * 101 | * ViewCounterInterface $viewcounter The viewcounter entity. 102 | * 103 | * @return self 104 | */ 105 | public function build(ViewCounterInterface $viewcounter): self 106 | { 107 | $this->total++; 108 | 109 | return $this; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Statistics/SecondTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | /** 18 | * Trait SecondTrait 19 | */ 20 | trait SecondTrait 21 | { 22 | protected $s00; 23 | protected $s01; 24 | protected $s02; 25 | protected $s03; 26 | protected $s04; 27 | protected $s05; 28 | protected $s06; 29 | protected $s07; 30 | protected $s08; 31 | protected $s09; 32 | protected $s10; 33 | protected $s11; 34 | protected $s12; 35 | protected $s13; 36 | protected $s14; 37 | protected $s15; 38 | protected $s16; 39 | protected $s17; 40 | protected $s18; 41 | protected $s19; 42 | protected $s20; 43 | protected $s21; 44 | protected $s22; 45 | protected $s23; 46 | protected $s24; 47 | protected $s25; 48 | protected $s26; 49 | protected $s27; 50 | protected $s28; 51 | protected $s29; 52 | protected $s30; 53 | protected $s31; 54 | protected $s32; 55 | protected $s33; 56 | protected $s34; 57 | protected $s35; 58 | protected $s36; 59 | protected $s37; 60 | protected $s38; 61 | protected $s39; 62 | protected $s40; 63 | protected $s41; 64 | protected $s42; 65 | protected $s43; 66 | protected $s44; 67 | protected $s45; 68 | protected $s46; 69 | protected $s47; 70 | protected $s48; 71 | protected $s49; 72 | protected $s50; 73 | protected $s51; 74 | protected $s52; 75 | protected $s53; 76 | protected $s54; 77 | protected $s55; 78 | protected $s56; 79 | protected $s57; 80 | protected $s58; 81 | protected $s59; 82 | 83 | /** 84 | * Gets the second. 85 | * 86 | * @param string $secondName The second name. 87 | * 88 | * @return Second|null The second. 89 | */ 90 | public function get(string $secondName): ?Second 91 | { 92 | return $this->$secondName; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Statistics/ViewDateTrait.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | 18 | use Tchoulom\ViewCounterBundle\Statistics\Date as ViewDate; 19 | use Tchoulom\ViewCounterBundle\Util\Date; 20 | 21 | /** 22 | * Trait ViewDateTrait 23 | */ 24 | trait ViewDateTrait 25 | { 26 | /** 27 | * The view dates. 28 | * 29 | * @var array 30 | */ 31 | protected $viewDates = []; 32 | 33 | /** 34 | * Gets the view dates. 35 | * 36 | * @return array 37 | */ 38 | public function getViewDates(): array 39 | { 40 | return $this->viewDates; 41 | } 42 | 43 | /** 44 | * Sets the view dates. 45 | * 46 | * @param array $viewDates The view dates. 47 | * 48 | * @return self 49 | */ 50 | public function setViewDates(array $viewDates): self 51 | { 52 | $this->viewDates = $viewDates; 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * Builds the view date. 59 | */ 60 | public function buildViewDate(): void 61 | { 62 | $date = $this->viewcounter->getViewDate(); 63 | $formattedDate = $date->format('Y-m-d H:i:s'); 64 | 65 | if (isset($this->viewDates[$formattedDate])) { 66 | $date = $this->viewDates[$formattedDate]; 67 | $date->build(); 68 | } else { 69 | $date = new ViewDate(1, $date); 70 | } 71 | 72 | $this->viewDates[$formattedDate] = $date; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Statistics/Year.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Statistics; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | use Tchoulom\ViewCounterBundle\Util\Date; 19 | 20 | /** 21 | * Class Year 22 | */ 23 | class Year 24 | { 25 | /** 26 | * The year number. 27 | * 28 | * @var int 29 | */ 30 | protected $yearNumber; 31 | 32 | /** 33 | * The total. 34 | * 35 | * @var int 36 | */ 37 | protected $total = 0; 38 | 39 | /** 40 | * The months. 41 | * 42 | * @var Month[] 43 | */ 44 | protected $months = []; 45 | 46 | /** 47 | * Year constructor. 48 | */ 49 | public function __construct() 50 | { 51 | $this->yearNumber = Date::getNowYear(); 52 | } 53 | 54 | /** 55 | * Gets the number of year. 56 | * 57 | * @return int 58 | */ 59 | public function getYearNumber(): int 60 | { 61 | return $this->yearNumber; 62 | } 63 | 64 | /** 65 | * Sets the number of year. 66 | * 67 | * @param int $yearNumber 68 | * 69 | * @return self 70 | */ 71 | public function setYearNumber(int $yearNumber): self 72 | { 73 | $this->yearNumber = $yearNumber; 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * Gets the total. 80 | * 81 | * @return int 82 | */ 83 | public function getTotal(): int 84 | { 85 | return $this->total; 86 | } 87 | 88 | /** 89 | * Sets the total. 90 | * 91 | * @param int $total 92 | * 93 | * @return self 94 | */ 95 | public function setTotal(int $total): self 96 | { 97 | $this->total = $total; 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | * Gets the months. 104 | * 105 | * @return Month[] 106 | */ 107 | public function getMonths(): array 108 | { 109 | return $this->months; 110 | } 111 | 112 | /** 113 | * Builds the month. 114 | * 115 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 116 | * 117 | * @return self 118 | */ 119 | public function buildMonth(ViewCounterInterface $viewcounter): self 120 | { 121 | $this->total++; 122 | $monthNumber = intval($viewcounter->getViewDate()->format('m')); 123 | 124 | if (isset($this->months[$monthNumber])) { 125 | $month = $this->months[$monthNumber]; 126 | } else { 127 | $month = new Month(); 128 | } 129 | 130 | $this->months[$monthNumber] = $month->buildWeek($viewcounter); 131 | 132 | return $this; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Storage/Database/MongoDB/DocumentStorageInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Storage\Database\MongoDB; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 18 | 19 | /** 20 | * Interface DocumentStorageInterface 21 | * 22 | * @package Tchoulom\ViewCounterBundle\Storage\Database 23 | */ 24 | interface DocumentStorageInterface 25 | { 26 | /** 27 | * Saves the statistics. 28 | * 29 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 30 | */ 31 | public function save(ViewCounterInterface $viewcounter); 32 | } 33 | -------------------------------------------------------------------------------- /Storage/Filesystem/FilesystemStorageInterface.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Storage\Filesystem; 16 | 17 | 18 | use Tchoulom\ViewCounterBundle\Entity\ViewCounterInterface; 19 | use Tchoulom\ViewCounterBundle\Model\ViewCountable; 20 | 21 | /** 22 | * Class FilesystemStorageInterface is used to manipulate the file system. 23 | */ 24 | interface FilesystemStorageInterface 25 | { 26 | /** 27 | * Saves the statistics. 28 | * 29 | * @param ViewCounterInterface $viewcounter The viewcounter entity. 30 | */ 31 | public function save(ViewCounterInterface $viewcounter); 32 | 33 | /** 34 | * Loads the contents. 35 | * 36 | * @return mixed 37 | */ 38 | public function loadContents(); 39 | 40 | /** 41 | * Gets the stats file name. 42 | * 43 | * @return string 44 | */ 45 | public function getStatsFileName(): string; 46 | 47 | /** 48 | * Gets the stats file extension. 49 | * 50 | * @return string|null 51 | */ 52 | public function getStatsFileExtension(): ?string; 53 | 54 | /** 55 | * Gets the full stats file name. 56 | * 57 | * @return string 58 | */ 59 | public function getFullStatsFileName(): string; 60 | 61 | /** 62 | * Gets the viewcounter directory. 63 | * 64 | * @return string 65 | */ 66 | public function getViewcounterDir(): string; 67 | 68 | /** 69 | * Creates a directory. 70 | * 71 | * @param $dirname 72 | * @param int $mode 73 | * @param bool $recursive 74 | */ 75 | public function mkdir($dirname, $mode = 0777, $recursive = true); 76 | 77 | /** 78 | * Opens a file. 79 | * 80 | * @param $filename 81 | * @param string $mode 82 | * 83 | * @return bool|resource 84 | */ 85 | public function fopen($filename, $mode = 'w'); 86 | 87 | /** 88 | * Writes to file. 89 | * 90 | * @param $file 91 | * @param $stats 92 | */ 93 | public function fwrite($file, $stats); 94 | 95 | /** 96 | * Closes an output file. 97 | * 98 | * @param $file 99 | */ 100 | public function fclose($file); 101 | } 102 | -------------------------------------------------------------------------------- /TchoulomViewCounterBundle.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle; 16 | 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | use Symfony\Component\HttpKernel\Bundle\Bundle; 19 | use Tchoulom\ViewCounterBundle\DependencyInjection\Compiler\ViewcounterPass; 20 | 21 | class TchoulomViewCounterBundle extends Bundle 22 | { 23 | /** 24 | * @param ContainerBuilder $container 25 | */ 26 | public function build(ContainerBuilder $container): void 27 | { 28 | parent::build($container); 29 | 30 | $container->addCompilerPass(new ViewcounterPass()); 31 | } 32 | 33 | /** 34 | * The supported view strategy. 35 | * 36 | * @var array 37 | */ 38 | const SUPPORTED_STRATEGY = ['on_refresh', 'unique_view', 'daily_view', 'hourly_view', 'weekly_view', 'monthly_view', 'yearly_view', 'view_per_minute', 'view_per_second']; 39 | 40 | /** 41 | * The supported statistics keys. 42 | * 43 | * @var array 44 | */ 45 | const SUPPORTED_STATS_KEYS = ['enabled', 'stats_file_name', 'stats_file_extension']; 46 | 47 | /** 48 | * The filesystem storage engine name. 49 | * 50 | * @var string 51 | */ 52 | const FILESYSTEM_STORAGE_ENGINE_NAME = 'filesystem'; 53 | 54 | /** 55 | * The mongodb storage engine name. 56 | * 57 | * @var string 58 | */ 59 | const MONGODB_STORAGE_ENGINE_NAME = 'mongodb'; 60 | } 61 | -------------------------------------------------------------------------------- /Tests/BaseTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Tests; 16 | 17 | use PHPUnit\Framework\TestCase; 18 | use Tchoulom\ViewCounterBundle\Storage\Filesystem\FilesystemStorageInterface; 19 | 20 | /** 21 | * Class BaseTest 22 | */ 23 | abstract class BaseTest extends TestCase 24 | { 25 | protected $clientIP = '127.0.0.1'; 26 | protected $filesystemStorageMock; 27 | protected $viewInterval = ['on_refresh', 'daily_view', 'unique_view', 'hourly_view', 'weekly_view', 'monthly_view', 'yearly_view', 'view_per_minute', 'view_per_second']; 28 | 29 | /** 30 | * Setup the fixtures. 31 | */ 32 | protected function setUp() 33 | { 34 | parent::setUp(); 35 | 36 | $this->filesystemStorageMock = $this->createMock(FilesystemStorageInterface::class); 37 | } 38 | 39 | /** 40 | * tearDown 41 | */ 42 | public function tearDown() 43 | { 44 | $this->filesystemStorageMock = null; 45 | } 46 | 47 | /** 48 | * Invokes a method. 49 | * 50 | * @param $object 51 | * @param $methodName 52 | * @param array $arguments 53 | * 54 | * @return mixed 55 | * 56 | * @throws \ReflectionException 57 | */ 58 | public function invokeMethod($object, $methodName, array $arguments = array()) 59 | { 60 | $reflection = new \ReflectionClass(get_class($object)); 61 | $method = $reflection->getMethod($methodName); 62 | $method->setAccessible(true); 63 | 64 | return $method->invokeArgs($object, $arguments); 65 | } 66 | 67 | /** 68 | * Sets a protected property on a given object via reflection 69 | * 70 | * @param $object Instance in which protected value is being modified 71 | * @param $property Property on instance being modified 72 | * @param $value New value of the property being modified 73 | * 74 | * @return void 75 | * 76 | * @throws \ReflectionException 77 | */ 78 | public function setProtectedProperty($object, $property, $value) 79 | { 80 | $reflection = new \ReflectionClass($object); 81 | $reflectionProperty = $reflection->getProperty($property); 82 | $reflectionProperty->setAccessible(true); 83 | $reflectionProperty->setValue($object, $value); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Tests/DependencyInjection/TchoulomViewCounterExtensionTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Tests\DependencyInjection; 16 | 17 | use Tchoulom\ViewCounterBundle\DependencyInjection\TchoulomViewCounterExtension; 18 | use Tchoulom\ViewCounterBundle\Tests\BaseTest; 19 | 20 | /** 21 | * Class TchoulomViewCounterExtensionTest 22 | */ 23 | class TchoulomViewCounterExtensionTest extends BaseTest 24 | { 25 | protected $viewCounterExtension; 26 | 27 | /** 28 | * Setup the fixtures. 29 | */ 30 | protected function setUp() 31 | { 32 | parent::setUp(); 33 | 34 | $this->viewCounterExtension = new TchoulomViewCounterExtension(); 35 | } 36 | 37 | /** 38 | * tearDown 39 | */ 40 | public function tearDown() 41 | { 42 | parent::tearDown(); 43 | 44 | $this->viewCounterExtension = null; 45 | } 46 | 47 | /** 48 | * tests postProcessSuccess 49 | * 50 | * @dataProvider postProcessProvider 51 | */ 52 | public function testPostProcessSuccess($configs) 53 | { 54 | $uniqueElt = $this->viewCounterExtension->postProcess($configs); 55 | 56 | $this->assertTrue(is_array($uniqueElt)); 57 | } 58 | 59 | /** 60 | * tests postProcessError 61 | * 62 | * @expectedException \Tchoulom\ViewCounterBundle\Exception\RuntimeException 63 | * @expectedExceptionMessage You must choose one of the following values: on_refresh, unique_view, daily_view, hourly_view, weekly_view, monthly_view, yearly_view, view_per_minute, view_per_second. 64 | */ 65 | public function testPostProcessError($configs = null) 66 | { 67 | $this->viewCounterExtension->postProcess($configs); 68 | } 69 | 70 | /** 71 | * @return array 72 | */ 73 | public function postProcessProvider() 74 | { 75 | return [ 76 | [ 77 | [ 78 | ['view_counter' => ['daily_view' => 1]] 79 | ] 80 | ] 81 | ]; 82 | } 83 | } -------------------------------------------------------------------------------- /Tests/Entity/ViewCounterTest.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Tests\Entity; 16 | 17 | use Tchoulom\ViewCounterBundle\Entity\ViewCounter; 18 | use Tchoulom\ViewCounterBundle\Tests\BaseTest; 19 | 20 | /** 21 | * Class ViewCounterTest 22 | */ 23 | class ViewCounterTest extends BaseTest 24 | { 25 | /** 26 | * Setup the fixtures. 27 | */ 28 | protected function setUp() 29 | { 30 | parent::setUp(); 31 | } 32 | 33 | /** 34 | * tearDown 35 | */ 36 | public function tearDown() 37 | { 38 | parent::tearDown(); 39 | } 40 | 41 | /** 42 | * tests GetIp 43 | */ 44 | public function testGetIp() 45 | { 46 | $thisEntity = $this->viewCounterEntity->setIp($this->clientIP); 47 | 48 | $this->assertInstanceOf(ViewCounter::class, $thisEntity); 49 | $this->assertTrue(is_string($this->viewCounterEntity->getIp())); 50 | } 51 | 52 | /** 53 | * tests ViewDate 54 | */ 55 | public function testViewDate() 56 | { 57 | $entityViewed = $this->viewCounterEntity->setViewDate($this->viewDate); 58 | 59 | $this->assertInstanceOf(ViewCounter::class, $entityViewed); 60 | $this->assertTrue(is_numeric($this->viewCounterEntity->getViewDate()->getTimestamp())); 61 | } 62 | } -------------------------------------------------------------------------------- /Util/ReflectionExtractor.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * (c) Ernest TCHOULOM 10 | * 11 | * For the full copyright and license information, please view the LICENSE 12 | * file that was distributed with this source code. 13 | */ 14 | 15 | namespace Tchoulom\ViewCounterBundle\Util; 16 | 17 | /** 18 | * Class ReflectionExtractor 19 | */ 20 | class ReflectionExtractor 21 | { 22 | /** 23 | * Gets the short class name. 24 | * 25 | * @param $class 26 | * 27 | * @return string 28 | * 29 | * @throws \ReflectionException 30 | */ 31 | public static function getShortClassName($class): string 32 | { 33 | return (new \ReflectionClass($class))->getShortName(); 34 | } 35 | 36 | /** 37 | * Gets the class name. 38 | * 39 | * @param $class 40 | * 41 | * @return string 42 | * 43 | * @throws \ReflectionException 44 | */ 45 | public static function getClassName($class): string 46 | { 47 | return strtolower(self::getShortClassName($class)); 48 | } 49 | 50 | /** 51 | * Gets the class name pluralized. 52 | * 53 | * @param $class 54 | * 55 | * @return string 56 | * 57 | * @throws \ReflectionException 58 | */ 59 | public static function getClassNamePluralized($class): string 60 | { 61 | return self::getClassName($class) . 's'; 62 | } 63 | 64 | /** 65 | * Gets the full class name. 66 | * 67 | * @param $class 68 | * 69 | * @return string The full 70 | */ 71 | public static function getFullClassName($class): string 72 | { 73 | return get_class($class); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tchoulom/view-counter-bundle", 3 | "license": "MIT", 4 | "type": "symfony-bundle", 5 | "description": "The \"View Counter\" bundle", 6 | "keywords": ["view counter", "view counter symfony", "statistics", "statistics bundle", "statistics symfony","statistics of web pages", "Google Charts", "view counter bundle", "Count the number of views of a page", "pages views counter", "view count", "viewership", "viewership measurement", "page views", "page view count", "view counter interface"], 7 | "authors": [ 8 | { 9 | "name": "Ernest TCHOULOM", 10 | "email": "tchoulomernest@gmail.com", 11 | "homepage": "https://www.linkedin.com/in/ernest-tchoulom-69422025/" 12 | } 13 | ], 14 | "autoload": { 15 | "psr-4": { 16 | "Tchoulom\\ViewCounterBundle\\": "" 17 | }, 18 | "exclude-from-classmap": [ 19 | "/Tests/" 20 | ] 21 | }, 22 | "require": { 23 | "php": ">=8.0.2", 24 | "symfony/framework-bundle": "^6.0|^7.0" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": ">5.7" 28 | }, 29 | "minimum-stability": "stable" 30 | } 31 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | tests 18 | 19 | 20 | 21 | 22 | 23 | src 24 | 25 | src/*Bundle/Resources 26 | src/*/*Bundle/Resources 27 | src/*/Bundle/*Bundle/Resources 28 | 29 | 30 | 31 | 32 | --------------------------------------------------------------------------------