1<?php 2/** 3 * Matomo - free/libre analytics platform 4 * 5 * @link https://matomo.org 6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later 7 */ 8namespace Piwik\Plugins\TagManager\Model; 9 10use Piwik\Container\StaticContainer; 11use Piwik\Piwik; 12use Piwik\Plugins\TagManager\Context\BaseContext; 13use Piwik\Plugins\TagManager\Dao\ContainerReleaseDao; 14use Piwik\Plugins\TagManager\Dao\ContainersDao; 15use Piwik\Plugins\TagManager\Context\ContextProvider; 16use Piwik\Plugins\TagManager\Dao\ContainerVersionsDao; 17use Exception; 18use Piwik\Plugins\TagManager\Input\Description; 19use Piwik\Plugins\TagManager\Input\IdSite; 20use Piwik\Plugins\TagManager\Input\Name; 21use Piwik\Plugins\TagManager\Model\Container\ContainerIdGenerator; 22 23 24class Container extends BaseModel 25{ 26 27 /** 28 * @var ContainersDao 29 */ 30 private $dao; 31 32 /** 33 * @var ContextProvider 34 */ 35 private $contextProvider; 36 37 /** 38 * @var ContainerVersionsDao 39 */ 40 private $versionsDao; 41 42 /** 43 * @var ContainerReleaseDao 44 */ 45 private $releasesDao; 46 47 /** 48 * @var ContainerIdGenerator 49 */ 50 private $containerIdGenerator; 51 52 /** 53 * @var Environment 54 */ 55 private $environment; 56 57 public function __construct(ContainersDao $containersDao, ContainerVersionsDao $containerVersionsDao, ContainerReleaseDao $containerPublishesDao, ContextProvider $contextProvider, ContainerIdGenerator $containerIdGenerator, Environment $environment) 58 { 59 $this->dao = $containersDao; 60 $this->versionsDao = $containerVersionsDao; 61 $this->releasesDao = $containerPublishesDao; 62 $this->contextProvider = $contextProvider; 63 $this->containerIdGenerator = $containerIdGenerator; 64 $this->environment = $environment; 65 } 66 67 public function getNumContainersTotal() 68 { 69 return $this->dao->getNumContainersTotal(); 70 } 71 72 public function getNumContainersInSite($idSite) 73 { 74 return $this->dao->getNumContainersInSite($idSite); 75 } 76 77 public function enablePreviewMode($idSite, $idContainer, $idContainerVersion, $releaseLogin) 78 { 79 $idContainerRelease = $this->publishVersion($idSite, $idContainer, $idContainerVersion, Environment::ENVIRONMENT_PREVIEW, $releaseLogin); 80 $this->generateContainer($idSite, $idContainer); 81 return $idContainerRelease; 82 } 83 84 public function disablePreviewMode($idSite, $idContainer) 85 { 86 $date = $this->getCurrentDateTime(); 87 $this->releasesDao->deleteAllVersionsForRelease($idSite, $idContainer, Environment::ENVIRONMENT_PREVIEW, $date); 88 $this->generateContainer($idSite, $idContainer); 89 } 90 91 public function generateContainerIfHasPreviewRelease($idSite, $idContainer) 92 { 93 $container = $this->getContainer($idSite, $idContainer); 94 95 if (!empty($container['releases'])) { 96 foreach ($container['releases'] as $release) { 97 if ($release['environment'] === Environment::ENVIRONMENT_PREVIEW) { 98 99 // we only want to regenerate the containers if it has a preview enabled 100 $context = $this->contextProvider->getContext($container['context']); 101 if ($context) { 102 return $context->generate($container); 103 } 104 } 105 } 106 } 107 } 108 109 public function hasPreviewRelease($idSite, $idContainer) 110 { 111 $release = $this->releasesDao->getReleaseForContainerVersion($idSite, $idContainer, Environment::ENVIRONMENT_PREVIEW); 112 113 return !empty($release); 114 } 115 116 public function generateContainer($idSite, $idContainer) 117 { 118 $container = $this->getContainer($idSite, $idContainer); 119 120 if (!empty($container)) { 121 $context = $this->contextProvider->getContext($container['context']); 122 if ($context) { 123 return $context->generate($container); 124 } 125 } 126 } 127 128 public function getContainerInstallInstructions($idSite, $idContainer, $environment) 129 { 130 $this->checkContainerExists($idSite, $idContainer); 131 $this->environment->checkIsValidEnvironment($environment); 132 133 $container = $this->dao->getContainer($idSite, $idContainer); 134 135 if (!empty($container)) { 136 $context = $this->contextProvider->getContext($container['context']); 137 if ($context) { 138 return $context->getInstallInstructions($container, $environment); 139 } 140 } 141 } 142 143 private function validateContainer($idSite, $name, $description) 144 { 145 $site = new IdSite($idSite); 146 $site->check(); 147 148 $name = new Name($name); 149 $name->check(); 150 151 $description = new Description($description); 152 $description->check(); 153 } 154 155 public function addContainer($idSite, $context, $name, $description) 156 { 157 $this->validateContainer($idSite, $name, $description); 158 $this->contextProvider->checkIsValidContext($context); 159 160 $createdDate = $this->getCurrentDateTime(); 161 162 $idContainer = $this->containerIdGenerator->generateId(); 163 164 $this->dao->createContainer($idSite, $idContainer, $context, $name, $description, $createdDate); 165 166 $this->versionsDao->createDraftVersion($idSite, $idContainer, $createdDate); 167 168 $this->generateContainer($idSite, $idContainer); 169 170 return $idContainer; 171 } 172 173 public function updateContainer($idSite, $idContainer, $name, $description) 174 { 175 $this->validateContainer($idSite, $name, $description); 176 177 $columns = array( 178 'name' => $name, 179 'description' => $description 180 ); 181 $this->updateContainerColumns($idSite, $idContainer, $columns); 182 $this->generateContainer($idSite, $idContainer); 183 } 184 185 public function checkContainerExists($idSite, $idContainer) 186 { 187 $container = $this->dao->getContainer($idSite, $idContainer); 188 189 if (empty($container)) { 190 throw new Exception(Piwik::translate('TagManager_ErrorContainerDoesNotExist', $idContainer)); 191 } 192 } 193 194 public function getContainers($idSite) 195 { 196 $containers = $this->dao->getContainersForSite($idSite); 197 return $this->enrichContainers($containers); 198 } 199 200 public function deleteContainer($idSite, $idContainer) 201 { 202 $deletedDate = $this->getCurrentDateTime(); 203 $this->dao->deleteContainer($idSite, $idContainer, $deletedDate); 204 205 // we remove them to no longer expose any information to any user/visitor, as a Matomo user would assume the 206 // data has been removed 207 BaseContext::removeAllContainerFiles($idContainer); 208 } 209 210 public function getContainer($idSite, $idContainer) 211 { 212 $container = $this->dao->getContainer($idSite, $idContainer); 213 214 return $this->enrichContainer($container); 215 } 216 217 public function checkContainerVersionExists($idSite, $idContainer, $idContainerVersion) 218 { 219 $this->checkContainerExists($idSite, $idContainer); 220 221 $version = $this->versionsDao->getVersion($idSite, $idContainer, $idContainerVersion); 222 223 if (empty($version)) { 224 throw new Exception(Piwik::translate('TagManager_ErrorContainerVersionDoesNotExist')); 225 } 226 } 227 228 public function createContainerVersion($idSite, $idContainer, $idContainerVersion, $name, $description) 229 { 230 $this->checkContainerVersionExists($idSite, $idContainer, $idContainerVersion); 231 $this->validateContainerVersion($idSite, $name, $description); 232 $createdDate = $this->getCurrentDateTime(); 233 234 // create a new version 235 $newIdContainerVersion = $this->versionsDao->createVersion($idSite, $idContainer, $name, $description, $createdDate); 236 237 // we need to use staticContainer and not in constructor as they would require each other in the constructor and result in a loop 238 $export = $this->getExport(); 239 $exported = $export->exportContainerVersion($idSite, $idContainer, $idContainerVersion); 240 $import = StaticContainer::get('Piwik\Plugins\TagManager\API\Import'); 241 $import->importContainerVersion($exported, $idSite, $idContainer, $newIdContainerVersion); 242 243 return $newIdContainerVersion; 244 } 245 246 public function updateContainerVersion($idSite, $idContainer, $idContainerVersion, $name, $description) 247 { 248 $this->validateContainerVersion($idSite, $name, $description); 249 250 $columns = array( 251 'name' => $name, 252 'description' => $description, 253 'updated_date' => $this->getCurrentDateTime() 254 ); 255 $this->versionsDao->updateContainerColumns($idSite, $idContainer, $idContainerVersion, $columns); 256 $this->generateContainer($idSite, $idContainer); 257 } 258 259 public function deleteContainerVersion($idSite, $idContainer, $idContainerVersion) 260 { 261 $version = $this->getContainerVersion($idSite, $idContainer, $idContainerVersion); 262 if (!empty($version)) { 263 if (empty($version['revision'])) { 264 throw new Exception(Piwik::translate('TagManager_ErrorVersionCannotBeDeleted', Piwik::translate('TagManager_Draft'))); 265 } 266 if (!empty($version['releases'])) { 267 throw new Exception(Piwik::translate('TagManager_ErrorVersionCannotBeDeletedAsPublished')); 268 } 269 $this->versionsDao->deleteVersion($idSite, $idContainerVersion, $this->getCurrentDateTime()); 270 } 271 } 272 273 /** 274 * @param $idSite 275 * @param $idContainer 276 * @param $idContainerVersion 277 * @return array|bool 278 */ 279 public function getContainerVersion($idSite, $idContainer, $idContainerVersion) 280 { 281 $version = $this->versionsDao->getVersion($idSite, $idContainer, $idContainerVersion); 282 283 return $this->enrichContainerVersion($version); 284 } 285 286 public function getContainerVersions($idSite, $idContainer) 287 { 288 $versions = $this->versionsDao->getVersionsOfContainer($idSite, $idContainer); 289 290 return $this->enrichContainerVersions($versions); 291 } 292 293 public function checkContainerReleaseExists($idSite, $idContainer, $environment) 294 { 295 $this->checkContainerExists($idSite, $idContainer); 296 297 $release = $this->releasesDao->getReleaseForContainerVersion($idSite, $idContainer, $environment); 298 299 if (empty($release)) { 300 throw new Exception(Piwik::translate('TagManager_ErrorContainerReleaseDoesNotExist')); 301 } 302 } 303 304 public function publishVersion($idSite, $idContainer, $idContainerVersion, $environment, $releaseLogin) 305 { 306 $this->checkContainerVersionExists($idSite, $idContainer, $idContainerVersion); 307 // there is on purpose no validation for environment name as it may be used with eg preview etc. 308 309 $publishDate = $this->getCurrentDateTime(); 310 $idContainerRelease = $this->releasesDao->releaseVersion($idSite, $idContainer, $idContainerVersion, $environment, $releaseLogin, $publishDate); 311 $this->generateContainer($idSite, $idContainer); 312 return $idContainerRelease; 313 } 314 315 private function validateContainerVersion($idSite, $versionName, $versionDescription) 316 { 317 $site = new IdSite($idSite); 318 $site->check(); 319 320 $name = new Name($versionName); 321 $name->check(); 322 323 $description = new Description($versionDescription); 324 $description->check(); 325 } 326 327 public function getAllReleasedContainers() 328 { 329 $containers = $this->releasesDao->getAllReleasedContainers(); 330 foreach ($containers as $index => $container) { 331 $containers[$index]['idsite'] = (int) $container['idsite']; 332 } 333 return $containers; 334 } 335 336 public function getActiveContainersInfo() 337 { 338 $containers = $this->dao->getActiveContainersInfo(); 339 foreach ($containers as $index => $container) { 340 $containers[$index]['idsite'] = (int) $container['idsite']; 341 } 342 return $containers; 343 } 344 345 private function updateContainerColumns($idSite, $idContainer, $columns) 346 { 347 if (!isset($columns['updated_date'])) { 348 $columns['updated_date'] = $this->getCurrentDateTime(); 349 } 350 $this->dao->updateContainerColumns($idSite, $idContainer, $columns); 351 } 352 353 /** 354 * @return \Piwik\Plugins\TagManager\API\Export 355 */ 356 private function getExport() 357 { 358 return StaticContainer::get('Piwik\Plugins\TagManager\API\Export'); 359 } 360 361 private function enrichContainers($containers) 362 { 363 if (empty($containers)) { 364 return array(); 365 } 366 367 foreach ($containers as $index => $container) { 368 $containers[$index] = $this->enrichContainer($container); 369 } 370 371 return $containers; 372 } 373 374 private function enrichContainer($container) 375 { 376 if (empty($container)) { 377 return $container; 378 } 379 380 $container['created_date_pretty'] = $this->formatDate($container['created_date'], $container['idsite']); 381 $container['updated_date_pretty'] = $this->formatDate($container['updated_date'], $container['idsite']); 382 unset($container['deleted_date']); 383 $container['versions'] = $this->versionsDao->getVersionsOfContainer($container['idsite'], $container['idcontainer']); 384 $container['versions'] = $this->enrichContainerVersions($container['versions'], false); 385 $container['releases'] = $this->releasesDao->getReleasesOfContainer($container['idsite'], $container['idcontainer']); 386 $container['releases'] = $this->enrichContainerReleases($container['releases']); 387 $container['draft'] = $this->versionsDao->getDraftVersion($container['idsite'], $container['idcontainer']); 388 $container['draft'] = $this->enrichContainerVersion($container['draft'], false); 389 $container = $this->mixinSetVersionsAndReleases($container); 390 391 return $container; 392 } 393 394 private function mixinSetVersionsAndReleases($container) 395 { 396 foreach ($container['versions'] as $index => $version) { 397 $container['versions'][$index]['environments'] = array(); 398 } 399 400 foreach ($container['releases'] as &$release) { 401 $release['version_name'] = ''; 402 foreach ($container['versions'] as &$version) { 403 if ($release['idcontainerversion'] === $version['idcontainerversion']) { 404 $release['version_name'] = $version['name']; 405 $version['environments'][] = $release['environment']; 406 } 407 } 408 } 409 return $container; 410 } 411 412 private function enrichContainerVersions($containerVersions, $fetchReleases = true) 413 { 414 if (empty($containerVersions)) { 415 return array(); 416 } 417 418 foreach ($containerVersions as $index => $containerVersion) { 419 $containerVersions[$index] = $this->enrichContainerVersion($containerVersion, $fetchReleases); 420 } 421 422 return $containerVersions; 423 } 424 425 private function enrichContainerVersion($containerVersion, $fetchReleases = true) 426 { 427 if (empty($containerVersion)) { 428 return $containerVersion; 429 } 430 431 $containerVersion['created_date_pretty'] = $this->formatDate($containerVersion['created_date'], $containerVersion['idsite']); 432 $containerVersion['updated_date_pretty'] = $this->formatDate($containerVersion['updated_date'], $containerVersion['idsite']); 433 unset($containerVersion['deleted_date']); 434 if ($fetchReleases) { 435 $containerVersion['releases'] = $this->releasesDao->getReleasesForContainerVersion($containerVersion['idsite'], $containerVersion['idcontainer'], $containerVersion['idcontainerversion']); 436 $containerVersion['releases'] = $this->enrichContainerReleases($containerVersion['releases']); 437 } 438 439 return $containerVersion; 440 } 441 442 private function enrichContainerReleases($containerReleases) 443 { 444 if (empty($containerReleases)) { 445 return array(); 446 } 447 448 foreach ($containerReleases as $index => $containerRelease) { 449 $containerReleases[$index] = $this->enrichContainerRelease($containerRelease); 450 } 451 452 return $containerReleases; 453 } 454 455 private function enrichContainerRelease($containerRelease) 456 { 457 if (empty($containerRelease)) { 458 return $containerRelease; 459 } 460 461 $containerRelease['release_date_pretty'] = $this->formatDate($containerRelease['release_date'], $containerRelease['idsite']); 462 unset($containerRelease['deleted_date']); 463 464 return $containerRelease; 465 } 466} 467 468