partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit b633d4de58e87134111a05b1e04d4c9d17e77053
parent fc0ef55ea98d18cda7f443ec8d6d777ca647492e
Author: Felicitus <felicitus@felicitus.org>
Date:   Fri, 25 Sep 2015 21:38:09 +0200

Added JMS Translator (mainly due to automatic extraction of locale strings from bundles), added SystemNotice service and added several functional tests

Diffstat:
Mapp/AppKernel.php | 1+
Mapp/config/config.yml | 34+++++++++++++++++++++++++++++++++-
Mcomposer.json | 3++-
Mcomposer.lock | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/PartKeepr/AuthBundle/Resources/translations/messages.fr.xlf | 1+
Asrc/PartKeepr/CoreBundle/Action/SystemNoticeAcknowledgeAction.php | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/CoreBundle/DependencyInjection/PartKeeprCoreExtension.php | 1+
Asrc/PartKeepr/CoreBundle/Entity/SystemNotice.php | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/CoreBundle/PartKeeprVersion.php | 16++++++++++++++++
Asrc/PartKeepr/CoreBundle/Resources/config/actions.xml | 14++++++++++++++
Msrc/PartKeepr/CoreBundle/Resources/config/services.xml | 13++++++++++---
Asrc/PartKeepr/CoreBundle/Services/SystemNoticeService.php | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/CoreBundle/Services/SystemService.php | 17+++++++++++------
Asrc/PartKeepr/CoreBundle/Services/VersionService.php | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/CoreBundle/Tests/Fixtures/versions.json | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/CoreBundle/Tests/SystemInformationTest.php | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/CoreBundle/Tests/SystemNoticeTest.php | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/CoreBundle/Tests/VersionServiceTest.php | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/SystemNotice/SystemNoticeEditor.js | 139++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/SystemNotice/SystemNoticeEditorComponent.js | 38++++++++++++++++++++------------------
Dsrc/backend/PartKeepr/PartDistributor/PartDistributorManager.php | 75---------------------------------------------------------------------------
Dsrc/backend/PartKeepr/PartDistributor/PartDistributorService.php | 85-------------------------------------------------------------------------------
Msrc/backend/PartKeepr/PartKeepr.php | 591+++++++++++++++++++++++++++++++++++++++----------------------------------------
Dsrc/backend/PartKeepr/PartKeeprVersion.php | 16----------------
Dsrc/backend/PartKeepr/SystemNotice/SystemNotice.php | 143-------------------------------------------------------------------------------
Dsrc/backend/PartKeepr/SystemNotice/SystemNoticeManager.php | 56--------------------------------------------------------
Dsrc/backend/PartKeepr/SystemNotice/SystemNoticeService.php | 84-------------------------------------------------------------------------------
27 files changed, 1136 insertions(+), 883 deletions(-)

diff --git a/app/AppKernel.php b/app/AppKernel.php @@ -69,6 +69,7 @@ class AppKernel extends Kernel new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(), new Brainbits\FugueIconsBundle\BrainbitsFugueIconsBundle(), new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), + new JMS\TranslationBundle\JMSTranslationBundle(), ); // Developer bundles diff --git a/app/config/config.yml b/app/config/config.yml @@ -30,7 +30,7 @@ sensio_framework_extra: framework: #esi: ~ - #translator: { fallback: %locale% } + translator: { fallback: en } serializer: { enable_annotations: true } secret: %secret% router: @@ -1097,3 +1097,35 @@ services: - method: "initDenormalizationContext" arguments: - { groups: [ "default" ] } + + resource.system_notice.item_operation.get: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createItemOperation" ] + arguments: [ "@resource.system_notice", "GET" ] + + resource.system_notice.item_operation.acknowledge: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createItemOperation" ] + arguments: + - "@resource.system_notice" # Resource + - [ "PUT" ] # Methods + - "/system_notices/{id}/acknowledge" # Path + - "partkeepr.system_notice.acknowledge" # Controller + - "SystemNoticeAcknowledge" # Route name + + resource.system_notice: + parent: "api.resource" + arguments: [ "PartKeepr\\CoreBundle\\Entity\\SystemNotice" ] + tags: [ { name: "api.resource" } ] + calls: + - method: "initItemOperations" + arguments: [ [ "@resource.system_notice.item_operation.get", "@resource.system_notice.item_operation.acknowledge" ] ] + - method: "initFilters" + arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] + - method: "initNormalizationContext" + arguments: [ { groups: [ "default" ] } ] + - method: "initDenormalizationContext" + arguments: + - { groups: [ "default" ] } diff --git a/composer.json b/composer.json @@ -57,7 +57,8 @@ "friendsofsymfony/user-bundle": "~2.0@dev", "escapestudios/wsse-authentication-bundle": "2.3.x-dev", "atelierspierrot/famfamfam-silk-sprite": "^1.0", - "reputation-vip/composer-assets-installer": "^1.0" + "reputation-vip/composer-assets-installer": "^1.0", + "jms/translation-bundle": "dev-master" }, "require-dev": { "phpunit/phpunit": "4.8.*", diff --git a/composer.lock b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "794f38fae005e121c893b2d5e0982160", + "hash": "89fe89830a0016838b97be2856adfa05", "packages": [ { "name": "atelierspierrot/famfamfam-silk-sprite", @@ -1910,6 +1910,78 @@ "time": "2014-01-12 16:20:24" }, { + "name": "jms/translation-bundle", + "version": "dev-master", + "target-dir": "JMS/TranslationBundle", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/JMSTranslationBundle.git", + "reference": "8eff56746b73762dfe06414faf0fb609bfe51754" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/JMSTranslationBundle/zipball/8eff56746b73762dfe06414faf0fb609bfe51754", + "reference": "8eff56746b73762dfe06414faf0fb609bfe51754", + "shasum": "" + }, + "require": { + "nikic/php-parser": "0.9.4", + "symfony/console": "*", + "symfony/framework-bundle": "~2.1" + }, + "conflict": { + "twig/twig": "1.10.2" + }, + "require-dev": { + "jms/di-extra-bundle": ">=1.1", + "sensio/framework-extra-bundle": "*", + "symfony/browser-kit": "*", + "symfony/class-loader": "*", + "symfony/css-selector": "*", + "symfony/finder": "*", + "symfony/form": "*", + "symfony/process": "*", + "symfony/security": "*", + "symfony/twig-bundle": "*", + "symfony/validator": "*", + "symfony/yaml": "*" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-0": { + "JMS\\TranslationBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Puts the Symfony2 Translation Component on steroids", + "homepage": "http://jmsyst.com/bundles/JMSTranslationBundle", + "keywords": [ + "extract", + "extraction", + "i18n", + "interface", + "multilanguage", + "translation", + "ui", + "webinterface" + ], + "time": "2014-10-29 13:23:47" + }, + { "name": "kriswallsmith/assetic", "version": "v1.3.0", "source": { @@ -2232,20 +2304,19 @@ }, { "name": "nikic/php-parser", - "version": "v0.9.5", + "version": "v0.9.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb" + "reference": "1e5e280ae88a27effa2ae4aa2bd088494ed8594f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ef70767475434bdb3615b43c327e2cae17ef12eb", - "reference": "ef70767475434bdb3615b43c327e2cae17ef12eb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1e5e280ae88a27effa2ae4aa2bd088494ed8594f", + "reference": "1e5e280ae88a27effa2ae4aa2bd088494ed8594f", "shasum": "" }, "require": { - "ext-tokenizer": "*", "php": ">=5.2" }, "type": "library", @@ -2273,7 +2344,7 @@ "parser", "php" ], - "time": "2014-07-23 18:24:17" + "time": "2013-08-25 17:11:40" }, { "name": "ocramius/proxy-manager", @@ -2947,12 +3018,12 @@ "version": "v2.7.0", "source": { "type": "git", - "url": "https://github.com/symfony/AsseticBundle.git", + "url": "https://github.com/symfony/assetic-bundle.git", "reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/AsseticBundle/zipball/3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", + "url": "https://api.github.com/repos/symfony/assetic-bundle/zipball/3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", "reference": "3ae5c8ca3079b6e0033cc9fbfb6500e2bc964da5", "shasum": "" }, @@ -3017,12 +3088,12 @@ "version": "2.7.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/DoctrineBridge.git", + "url": "https://github.com/symfony/doctrine-bridge.git", "reference": "783a83b50b688fc5be3becb92462bdc4511dc292" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/DoctrineBridge/zipball/783a83b50b688fc5be3becb92462bdc4511dc292", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/783a83b50b688fc5be3becb92462bdc4511dc292", "reference": "783a83b50b688fc5be3becb92462bdc4511dc292", "shasum": "" }, @@ -3086,12 +3157,12 @@ "version": "v2.7.1", "source": { "type": "git", - "url": "https://github.com/symfony/MonologBundle.git", + "url": "https://github.com/symfony/monolog-bundle.git", "reference": "9320b6863404c70ebe111e9040dab96f251de7ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/MonologBundle/zipball/9320b6863404c70ebe111e9040dab96f251de7ac", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/9320b6863404c70ebe111e9040dab96f251de7ac", "reference": "9320b6863404c70ebe111e9040dab96f251de7ac", "shasum": "" }, @@ -3145,12 +3216,12 @@ "version": "v2.3.8", "source": { "type": "git", - "url": "https://github.com/symfony/SwiftmailerBundle.git", + "url": "https://github.com/symfony/swiftmailer-bundle.git", "reference": "970b13d01871207e81d17b17ddda025e7e21e797" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/SwiftmailerBundle/zipball/970b13d01871207e81d17b17ddda025e7e21e797", + "url": "https://api.github.com/repos/symfony/swiftmailer-bundle/zipball/970b13d01871207e81d17b17ddda025e7e21e797", "reference": "970b13d01871207e81d17b17ddda025e7e21e797", "shasum": "" }, @@ -3199,20 +3270,20 @@ }, { "name": "symfony/symfony", - "version": "v2.7.4", + "version": "v2.7.5", "source": { "type": "git", "url": "https://github.com/symfony/symfony.git", - "reference": "1fdf23fe28876844b887b0e1935c9adda43ee645" + "reference": "619528a274647cffc1792063c3ea04c4fa8266a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/symfony/zipball/1fdf23fe28876844b887b0e1935c9adda43ee645", - "reference": "1fdf23fe28876844b887b0e1935c9adda43ee645", + "url": "https://api.github.com/repos/symfony/symfony/zipball/619528a274647cffc1792063c3ea04c4fa8266a0", + "reference": "619528a274647cffc1792063c3ea04c4fa8266a0", "shasum": "" }, "require": { - "doctrine/common": "~2.3", + "doctrine/common": "~2.4", "php": ">=5.3.9", "psr/log": "~1.0", "twig/twig": "~1.20|~2.0" @@ -3265,9 +3336,9 @@ }, "require-dev": { "doctrine/data-fixtures": "1.0.*", - "doctrine/dbal": "~2.2", + "doctrine/dbal": "~2.4", "doctrine/doctrine-bundle": "~1.2", - "doctrine/orm": "~2.2,>=2.2.3", + "doctrine/orm": "~2.4,>=2.4.5", "egulias/email-validator": "~1.2", "ircmaxell/password-compat": "~1.0", "monolog/monolog": "~1.11", @@ -3317,7 +3388,7 @@ "keywords": [ "framework" ], - "time": "2015-09-08 14:26:39" + "time": "2015-09-25 11:16:52" }, { "name": "twig/extensions", @@ -3677,16 +3748,16 @@ }, { "name": "zendframework/zend-stdlib", - "version": "2.7.2", + "version": "2.7.3", "source": { "type": "git", "url": "https://github.com/zendframework/zend-stdlib.git", - "reference": "130eaa89e24acbc6386af9061aabc78e1948b1f9" + "reference": "8ac0c77ff567fcf49b58689ee3bfa7595be102bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/130eaa89e24acbc6386af9061aabc78e1948b1f9", - "reference": "130eaa89e24acbc6386af9061aabc78e1948b1f9", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/8ac0c77ff567fcf49b58689ee3bfa7595be102bc", + "reference": "8ac0c77ff567fcf49b58689ee3bfa7595be102bc", "shasum": "" }, "require": { @@ -3731,7 +3802,7 @@ "stdlib", "zf2" ], - "time": "2015-09-23 13:11:47" + "time": "2015-09-25 04:06:33" } ], "packages-dev": [ @@ -4827,6 +4898,7 @@ "stof/doctrine-extensions-bundle": 20, "friendsofsymfony/user-bundle": 20, "escapestudios/wsse-authentication-bundle": 20, + "jms/translation-bundle": 20, "codeclimate/php-test-reporter": 20 }, "prefer-stable": false, diff --git a/src/PartKeepr/AuthBundle/Resources/translations/messages.fr.xlf b/src/PartKeepr/AuthBundle/Resources/translations/messages.fr.xlf @@ -9,3 +9,4 @@ </body> </file> </xliff> +N diff --git a/src/PartKeepr/CoreBundle/Action/SystemNoticeAcknowledgeAction.php b/src/PartKeepr/CoreBundle/Action/SystemNoticeAcknowledgeAction.php @@ -0,0 +1,57 @@ +<?php +namespace PartKeepr\CoreBundle\Action; + + +use Doctrine\ORM\EntityManager; +use Dunglas\ApiBundle\Action\ActionUtilTrait; +use Dunglas\ApiBundle\Exception\RuntimeException; +use Dunglas\ApiBundle\Model\DataProviderInterface; +use PartKeepr\CoreBundle\Entity\SystemNotice; +use Symfony\Component\HttpFoundation\Request; + +class SystemNoticeAcknowledgeAction +{ + use ActionUtilTrait; + + /** + * @var DataProviderInterface + */ + private $dataProvider; + + /** + * @var EntityManager + */ + private $entityManager; + + public function __construct( + DataProviderInterface $dataProvider, + EntityManager $entityManager + ) { + $this->dataProvider = $dataProvider; + $this->entityManager = $entityManager; + } + + /** + * Sets the acknowledged flag for a system notice + * + * @param Request $request The request + * @param int $id The ID of the system notice + * + * @return array|\Dunglas\ApiBundle\Model\PaginatorInterface|\Traversable + * + * @throws RuntimeException + */ + public function __invoke(Request $request, $id) + { + list($resourceType) = $this->extractAttributes($request); + + $systemNotice = $this->getItem($this->dataProvider, $resourceType, $id); + + /** + * @var $systemNotice SystemNotice + */ + $systemNotice->setAcknowledged(); + + $this->entityManager->flush(); + } +} diff --git a/src/PartKeepr/CoreBundle/DependencyInjection/PartKeeprCoreExtension.php b/src/PartKeepr/CoreBundle/DependencyInjection/PartKeeprCoreExtension.php @@ -31,6 +31,7 @@ class PartKeeprCoreExtension extends Extension $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.xml'); + $loader->load('actions.xml'); } public function getAlias() diff --git a/src/PartKeepr/CoreBundle/Entity/SystemNotice.php b/src/PartKeepr/CoreBundle/Entity/SystemNotice.php @@ -0,0 +1,158 @@ +<?php +namespace PartKeepr\CoreBundle\Entity; + +use Doctrine\ORM\Mapping as ORM; +use PartKeepr\DoctrineReflectionBundle\Annotation\TargetService; +use PartKeepr\Util\BaseEntity; +use Symfony\Component\Serializer\Annotation\Groups; + +/** + * Holds a system notice + * + * @ORM\Entity + * @TargetService("/api/system_notices") + **/ +class SystemNotice extends BaseEntity +{ + /** + * @ORM\Column(type="datetime") + * @Groups({"default"}) + * @var \DateTime + */ + private $date; + + /** + * @ORM\Column(type="string") + * @Groups({"default"}) + * @var string + */ + private $title; + + /** + * The description of this notice + * + * @ORM\Column(type="text") + * @Groups({"default"}) + * + * @var string + */ + private $description; + + /** + * Defines if the system notice has been acknowledged + * @ORM\Column(type="boolean") + * @Groups({"default"}) + * + * @var boolean + */ + private $acknowledged = false; + + /** + * Specifies the type. This is required for unique notices which shouldn't pop up every time we create them. + * @ORM\Column(type="string") + * @Groups({"default"}) + * + * @var string + */ + private $type; + + /** + * Sets the date and time for this entry + * + * @param \DateTime $date The date and time + */ + public function setDate(\DateTime $date) + { + $this->date = $date; + } + + /** + * Returns the date and time for this entry + * + * @return \DateTime the date and time for this entry + */ + public function getDate() + { + return $this->date; + } + + /** + * Sets the title for this entry + * + * @param string $title the title for this entry + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * Returns the title for this entry + * + * @return string the title + */ + public function getTitle() + { + return $this->title; + } + + /** + * Sets the description + * + * @param string $description + */ + public function setDescription($description) + { + $this->description = $description; + } + + /** + * Returns the description + * + * @return string The description + */ + public function getDescription() + { + return $this->description; + } + + /** + * Sets the value of the acknowledged flag + * + * @param boolean $bAck True if the notice should be acknowledged (default), false otherwise + */ + public function setAcknowledged($bAck = true) + { + $this->acknowledged = $bAck; + } + + /** + * Returns the value of the acknowledged flag + * + * @return boolean true if this notice has been acknowledged, false otherwise + */ + public function isAcknowledged() + { + return $this->acknowledged; + } + + /** + * Sets the type of this entry + * + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * Returns the type of this entry + * + * @return string The type + */ + public function getType() + { + return $this->type; + } +} diff --git a/src/PartKeepr/CoreBundle/PartKeeprVersion.php b/src/PartKeepr/CoreBundle/PartKeeprVersion.php @@ -0,0 +1,16 @@ +<?php +namespace PartKeepr\CoreBundle; + +class PartKeeprVersion +{ + /** + * Holds the PartKeepr Version. + * + * If {V_GIT}, then the function will return 'GIT Development Version'. + * {V_GIT} will be replaced by the build script with the actual version. + * + * The reason why we have a separate class for the version constant is that + * we can easily replace it from scripts. + */ + const PARTKEEPR_VERSION = '{V_GIT}'; +} diff --git a/src/PartKeepr/CoreBundle/Resources/config/actions.xml b/src/PartKeepr/CoreBundle/Resources/config/actions.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" ?> + +<container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + <services> + <service id="partkeepr.system_notice.acknowledge" + class="PartKeepr\CoreBundle\Action\SystemNoticeAcknowledgeAction"> + <argument type="service" id="api.data_provider"/> + <argument type="service" id="doctrine.orm.entity_manager"/> + </service> + </services> +</container> diff --git a/src/PartKeepr/CoreBundle/Resources/config/services.xml b/src/PartKeepr/CoreBundle/Resources/config/services.xml @@ -1,14 +1,21 @@ <?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="partkeepr_systemservice" class="PartKeepr\CoreBundle\Services\SystemService"> <argument type="service" id="doctrine"/> <argument type="service" id="service_container"/> + <argument type="service" id="partkeepr.versionservice"/> + </service> + <service id="partkeepr.systemnoticeservice" class="PartKeepr\CoreBundle\Services\SystemNoticeService"> + <argument type="service" id="doctrine.orm.entity_manager"/> + </service> + <service id="partkeepr.versionservice" class="PartKeepr\CoreBundle\Services\VersionService"> + <argument type="service" id="partkeepr.systemnoticeservice"/> + <argument type="service" id="translator"/> </service> - </services> </container> diff --git a/src/PartKeepr/CoreBundle/Services/SystemNoticeService.php b/src/PartKeepr/CoreBundle/Services/SystemNoticeService.php @@ -0,0 +1,43 @@ +<?php +namespace PartKeepr\CoreBundle\Services; + +use Doctrine\ORM\EntityManager; +use PartKeepr\CoreBundle\Entity\SystemNotice; +use Symfony\Component\DependencyInjection\ContainerAware; + +class SystemNoticeService extends ContainerAware +{ + /** + * @var EntityManager + */ + private $entityManager; + + public function __construct(EntityManager $entityManager) + { + $this->entityManager = $entityManager; + } + + public function createUniqueSystemNotice($type, $title, $description) + { + $dql = "SELECT sn FROM PartKeepr\CoreBundle\Entity\SystemNotice sn WHERE sn.type = :type"; + $query = $this->entityManager->createQuery($dql); + + $query->setParameter("type", $type); + + try { + $notice = $query->getSingleResult(); + } catch (\Exception $e) { + $notice = new SystemNotice(); + $this->entityManager->persist($notice); + } + + $notice->setDate(new \DateTime()); + $notice->setTitle($title); + $notice->setDescription($description); + $notice->setType($type); + + $this->entityManager->flush(); + + return $notice; + } +} diff --git a/src/PartKeepr/CoreBundle/Services/SystemService.php b/src/PartKeepr/CoreBundle/Services/SystemService.php @@ -2,17 +2,16 @@ namespace PartKeepr\CoreBundle\Services; use Doctrine\Bundle\DoctrineBundle\Registry; +use Doctrine\DBAL\Version as DBALVersion; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\ORM\Version as ORMVersion; use PartKeepr\CoreBundle\System\OperatingSystem; use PartKeepr\CoreBundle\System\SystemInformationRecord; use PartKeepr\CronLogger\CronLoggerManager; -use PartKeepr\PartKeepr; use PartKeepr\Util\Configuration; -use Doctrine\ORM\Version as ORMVersion; -use Doctrine\DBAL\Version as DBALVersion; -use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\DependencyInjection\ContainerInterface; class SystemService extends ContainerAware { @@ -21,10 +20,16 @@ class SystemService extends ContainerAware */ private $entityManager; - public function __construct(Registry $doctrine, Container $container) + /** + * @var VersionService + */ + private $versionService; + + public function __construct(Registry $doctrine, ContainerInterface $container, VersionService $versionService) { $this->entityManager = $doctrine->getManager(); $this->setContainer($container); + $this->versionService = $versionService; } /** @@ -62,7 +67,7 @@ class SystemService extends ContainerAware $aData[] = new SystemInformationRecord("Metadata Cache Implementation", $metadataCache, "PHP"); - $aData[] = new SystemInformationRecord("PartKeepr Version", PartKeepr::getVersion(), "PartKeepr"); + $aData[] = new SystemInformationRecord("PartKeepr Version", $this->versionService->getVersion(), "PartKeepr"); foreach (Configuration::getOptions() as $key => $value) { diff --git a/src/PartKeepr/CoreBundle/Services/VersionService.php b/src/PartKeepr/CoreBundle/Services/VersionService.php @@ -0,0 +1,113 @@ +<?php +namespace PartKeepr\CoreBundle\Services; + + +use PartKeepr\CoreBundle\PartKeeprVersion; +use Symfony\Component\Translation\TranslatorInterface; + +class VersionService +{ + /** + * @var SystemNoticeService + */ + private $systemNoticeService; + + /** + * @var string + */ + private $versionURI = "http://www.partkeepr.org/versions.json"; + + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var string + */ + private $version; + + public function __construct(SystemNoticeService $systemNoticeService, TranslatorInterface $translator) + { + $this->systemNoticeService = $systemNoticeService; + $this->translator = $translator; + + if (PartKeeprVersion::PARTKEEPR_VERSION == "{V_GIT}") { + $this->setVersion("GIT development version"); + } else { + $this->setVersion(PartKeeprVersion::PARTKEEPR_VERSION); + } + } + + public function setVersion($version) + { + $this->version = $version; + } + + public function getVersion() + { + return $this->version; + } + + public function setVersionURI($versionURI) + { + $this->versionURI = $versionURI; + } + + /** + * Checks against the versions at partkeepr.org. + * + * If a newer version was found, create a system notice entry. + */ + public function doVersionCheck() + { + if ($this->getVersion() === "{V_GIT}") { + return; + } + if (substr($this->getVersion(), 0, 17) === "partkeepr-nightly") { + return; + } + + $latestVersion = $this->getLatestVersion(); + + + if ($latestVersion === false) { + return; + } + + if (version_compare($this->getVersion(), $latestVersion["version"], '<')) { + $this->systemNoticeService->createUniqueSystemNotice( + "PARTKEEPR_VERSION_".$latestVersion["version"], + $this->translator->trans("New PartKeepr Version %version% available", + array("%version%" => $latestVersion["version"])), + $this->translator->trans("PartKeepr Version %version% changelog:", array( + "%version%" => $latestVersion["version"]."\n\n". + $latestVersion["changelog"], + )) + ); + + } + } + + public function getLatestVersion() + { + $data = file_get_contents($this->versionURI); + $versions = json_decode($data, true); + + if (!is_array($versions)) { + return false; + } + + $latestVersionEntry = $versions[0]; + + if (!array_key_exists("version", $latestVersionEntry)) { + return false; + } + + if (!array_key_exists("changelog", $latestVersionEntry)) { + return array("version" => $latestVersionEntry["version"], "changelog" => ""); + } else { + return array("version" => $latestVersionEntry["version"], "changelog" => $latestVersionEntry["changelog"]); + } + } +} diff --git a/src/PartKeepr/CoreBundle/Tests/Fixtures/versions.json b/src/PartKeepr/CoreBundle/Tests/Fixtures/versions.json @@ -0,0 +1,50 @@ +[ + { + "id": "8", + "version": "0.1.9", + "releasedate": "2013-05-03 13:21:02", + "changelog": "See https:\/\/wiki.partkeepr.org\/wiki\/New_and_Noteworthy\/0.1.9" + }, + { + "id": "7", + "version": "0.1.8", + "releasedate": "2012-11-05 17:10:32", + "changelog": "GUI Changes:\r\n\r\n* The Part Filter Panel now lets you filter by distributor and manufacturer \r\n* You can now remove the filter criteria for storage location, distributor and manufacturer directly now; previously, you had to click \"Reset\" to remove an active storage location filter \r\n* You can filter by the part create date\r\n* You can filter for all parts where no stock removals have taken place; this is useful to find parts you have never used and which you might remove from your inventory \r\n* The part filter columns now wrap to aid with smaller display sizes \r\n* A new part picker has been implemented, which has basically the same features as the regular grid, including the part filter panel. \r\n* The \"Create from Template\" button is now called \"Duplicate\" and supports duplicating of all part properties, including parameters, manufacturers, distributors and attachments. \r\n* The upload dialog now explains where the upload limit comes from and how to configure PHP to allow bigger uploads \r\n* Previously, you had to calculate the price per item manually if you had a package with, say, 100 items and only know the package price. PartKeepr now does that automatically; you can either fill in the price per item or the package price, and PartKeepr will calculate the other value for you. \r\n* In addition to the default layout, we also support a compact layout of the Part Manager which is helpful for small screens, like laptops.\r\n\r\nTechnical Changes: \r\n* Several queries have been optimized, so that the parts grid should load now much faster on slower systems \r\n* PartKeepr supports now xcache and memcache and you can now configure them. By default, APC is used (if available). \r\n* The frontend now supports individual JS files, instead of a large JS file. This is useful for debugging and can be enabled with the following configuration: Configuration::setOption(\"partkeepr.frontend.debug_all\", true); \r\n* Previously, we've used the bundled jsb3 builder from Sencha. However, that tool was using jsdb, a non-crossplatform binary chunk, which is now replaced with a generic minifier implementation, which uses either jsmin or optionally yui-compressor." + }, + { + "id": "6", + "version": "0.1.7", + "releasedate": "2012-05-29 05:57:16", + "changelog": "- Stock removals can now be commented\r\n- Display which projects a part is used in\r\n- Access the browser's context menu by holding \"ctrl\" and right-click\r\n- Added character map to input special characters not found on your keyboard (right-click input fields to access this feature)\r\n- Display part images in the part preview\r\n- Searching for multiple keywords is now supported\r\n- Added internal part number and description fields\r\n- A shortcut key (Alt+X) has been added to activate the part search field\r\n- Added initial currency support\r\n- Increased price field range to support a maximum of 999999999.9999\r\n- Many *many* bugfixes and usability improvements" + }, + { + "id": "5", + "version": "0.1.6.1", + "releasedate": "2012-04-11 17:49:15", + "changelog": "Changelog:\r\n* Removed D2 migrations, as they give problems while updating\r\n* Grid Export as CSV, XLS and Wiki " + }, + { + "id": "4", + "version": "0.1.6", + "releasedate": "2012-03-31 10:48:19", + "changelog": "Changelog:\r\n* Minimum required Doctrine2 version is now 2.2\r\n* Improved Exception dialog which aids debugging\r\n* Permission check when uploading files\r\n* Display Doctrine2 and PHP versions in the system information dialog\r\n* Remove empty distributors\/parameters\/manufacturers when editing parts, which caused errors\r\n* PHP 5.4 compatibility\r\n* Storage Location selection is now improved\r\n* Database connections now use UTF8 by default\r\n* Display all configuration parameters in the system information view\r\n* Category paths are now cached better; fixes several caching problems\r\n* Parts can now be found by their distributor number\r\n* Authentification can now be done via HTTP (and thus by external entities)" + }, + { + "id": "3", + "version": "0.1.5", + "releasedate": "2012-02-16 07:50:29", + "changelog": "- Compability with Doctrine 2.2\r\n- Improved config file handling during setup\r\n- Improved permission checks during setup\r\n- Several minor bugfixes" + }, + { + "id": "2", + "version": "0.1.1", + "releasedate": "2011-12-28 07:58:21", + "changelog": "* Bugfix for an issue where no parts are displayed after using the part filter panel\r\n* The data directory is now set correctly when using the installer\r\n* Check for the DoctrineSymfonyYaml package during setup\r\n* Added a project report view" + }, + { + "id": "1", + "version": "0.1", + "releasedate": "2011-12-25 07:57:53", + "changelog": "First public release" + } +]+ \ No newline at end of file diff --git a/src/PartKeepr/CoreBundle/Tests/SystemInformationTest.php b/src/PartKeepr/CoreBundle/Tests/SystemInformationTest.php @@ -0,0 +1,44 @@ +<?php +namespace PartKeepr\CoreBundle\Tests; + +use Liip\FunctionalTestBundle\Test\WebTestCase; + +class SystemInformationTest extends WebTestCase +{ + public function testSystemInformation() + { + $client = static::makeClient(true); + + $client->request( + 'GET', + '/api/system_information' + ); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertInternalType("array", $response); + + $this->assertInternalType("object", $response[0]); + $this->assertObjectHasAttribute("category", $response[0]); + $this->assertObjectHasAttribute("name", $response[0]); + $this->assertObjectHasAttribute("value", $response[0]); + } + + public function testSystemStatus() + { + $client = static::makeClient(true); + + $client->request( + 'GET', + '/api/system_status' + ); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertInternalType("object", $response); + $this->assertObjectHasAttribute("inactiveCronjobCount", $response); + $this->assertObjectHasAttribute("inactiveCronjobs", $response); + $this->assertInternalType("array", $response->inactiveCronjobs); + $this->assertObjectHasAttribute("schemaStatus", $response); + } +} diff --git a/src/PartKeepr/CoreBundle/Tests/SystemNoticeTest.php b/src/PartKeepr/CoreBundle/Tests/SystemNoticeTest.php @@ -0,0 +1,55 @@ +<?php +namespace PartKeepr\CoreBundle\Tests; + +use Dunglas\ApiBundle\Api\IriConverter; +use Liip\FunctionalTestBundle\Test\WebTestCase; + +class SystemNoticeTest extends WebTestCase +{ + public function setUp() + { + $this->loadFixtures(array()); + } + + public function testSystemNotices() + { + $client = static::makeClient(true); + + $systemNoticeService = $this->getContainer()->get("partkeepr.systemnoticeservice"); + $notice = $systemNoticeService->createUniqueSystemNotice("FOO", "BAR", "DING"); + + /** + * @var $iriConverter IriConverter + */ + $iriConverter = $this->getContainer()->get("api.iri_converter"); + + $iri = $iriConverter->getIriFromItem($notice); + $ackIri = $iri."/acknowledge"; + + + $client->request( + 'GET', + $iri + ); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertEquals("FOO", $response->type); + $this->assertEquals("BAR", $response->title); + $this->assertEquals("DING", $response->description); + $this->assertEquals(false, $response->acknowledged); + + $client->request( + 'PUT', + $ackIri + ); + + $client->request( + 'GET', + $iri + ); + + $response = json_decode($client->getResponse()->getContent()); + $this->assertEquals(true, $response->acknowledged); + } +} diff --git a/src/PartKeepr/CoreBundle/Tests/VersionServiceTest.php b/src/PartKeepr/CoreBundle/Tests/VersionServiceTest.php @@ -0,0 +1,43 @@ +<?php +namespace PartKeepr\CoreBundle\Tests; + +use Liip\FunctionalTestBundle\Test\WebTestCase; +use PartKeepr\CoreBundle\Services\VersionService; + +class VersionServiceTest extends WebTestCase +{ + public function setUp() + { + $this->loadFixtures(array()); + } + + public function testVersionService() + { + + /** + * @var VersionService $versionService + */ + $versionService = $this->getContainer()->get("partkeepr.versionservice"); + + $versionService->setVersion("0.1.8"); + $versionService->setVersionURI(__DIR__."/Fixtures/versions.json"); + + $versionService->doVersionCheck(); + + $client = static::makeClient(true); + + $client->request( + 'GET', + '/api/system_notices' + ); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertObjectHasAttribute("hydra:member", $response); + $this->assertEquals(1, count($response->{"hydra:member"})); + + $versionEntry = $response->{"hydra:member"}[0]; + + $this->assertEquals("New PartKeepr Version 0.1.9 available", $versionEntry->title); + } +} diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/SystemNotice/SystemNoticeEditor.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/SystemNotice/SystemNoticeEditor.js @@ -2,74 +2,76 @@ * Represents the system notice editor */ Ext.define('PartKeepr.SystemNoticeEditor', { - extend: 'PartKeepr.Editor', - alias: 'widget.SystemNoticeEditor', - - // Various style configurations - saveText: i18n("Save System Notice"), - defaults: { + extend: 'PartKeepr.Editor', + alias: 'widget.SystemNoticeEditor', + + // Various style configurations + saveText: i18n("Save System Notice"), + defaults: { anchor: '100%', labelWidth: 110 }, - layout: { - type: 'vbox', - align : 'stretch', - pack : 'start' - }, - enableButtons: false, - - /** - * Initializes the component - */ - initComponent: function () { - - this.acknowledgeButton = Ext.create("Ext.button.Button", { - text: i18n("Acknowledge Notice"), - icon: 'resources/silkicons/accept.png' - }); - - this.acknowledgeButton.on("click", this.onAcknowledgeClick, this); - - this.bottomToolbar = Ext.create("Ext.toolbar.Toolbar", { - enableOverflow: true, - margin: '10px', - defaults: {minWidth: 100}, - dock: 'bottom', - ui: 'footer', - items: [ this.acknowledgeButton ] - }); - - this.dockedItems = new Array(this.bottomToolbar); - - this.items = [{ - xtype: 'textfield', - readOnly: true, - name: 'title', - fieldLabel: i18n("Title") - },{ - xtype: 'textarea', - readOnly: true, - flex: 1, - name: 'description', - fieldLabel: i18n("Description") - },{ - xtype: 'datefield', - readOnly: true, - hideTrigger: true, - name: 'date', - fieldLabel: i18n("Date") - }]; - - this.callParent(); - }, - onAcknowledgeClick: function () { - var call = new PartKeepr.ServiceCall("SystemNotice", "acknowledge"); - call.setParameter("id", this.record.get("id")); - call.setHandler(Ext.bind(this.onAcknowledged, this)); - call.doCall(); - }, - onAcknowledged: function () { - this.fireEvent("editorClose", this); - this.store.load(); - } -});- \ No newline at end of file + layout: { + type: 'vbox', + align: 'stretch', + pack: 'start' + }, + enableButtons: false, + + /** + * Initializes the component + */ + initComponent: function () + { + + this.acknowledgeButton = Ext.create("Ext.button.Button", { + text: i18n("Acknowledge Notice"), + icon: 'resources/silkicons/accept.png' + }); + + this.acknowledgeButton.on("click", this.onAcknowledgeClick, this); + + this.bottomToolbar = Ext.create("Ext.toolbar.Toolbar", { + enableOverflow: true, + margin: '10px', + defaults: {minWidth: 100}, + dock: 'bottom', + ui: 'footer', + items: [this.acknowledgeButton] + }); + + this.dockedItems = new Array(this.bottomToolbar); + + this.items = [ + { + xtype: 'textfield', + readOnly: true, + name: 'title', + fieldLabel: i18n("Title") + }, { + xtype: 'textarea', + readOnly: true, + flex: 1, + name: 'description', + fieldLabel: i18n("Description") + }, { + xtype: 'datefield', + readOnly: true, + hideTrigger: true, + name: 'date', + fieldLabel: i18n("Date") + } + ]; + + this.callParent(); + }, + onAcknowledgeClick: function () + { + this.record.callAction("acknowledge", [], Ext.bind(this.onAcknowledged, this)); + }, + onAcknowledged: function () + { + this.fireEvent("editorClose", this); + this.store.load(); + } +}); diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/SystemNotice/SystemNoticeEditorComponent.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/SystemNotice/SystemNoticeEditorComponent.js @@ -2,20 +2,23 @@ * Represents the project editor component */ Ext.define('PartKeepr.SystemNoticeEditorComponent', { - extend: 'PartKeepr.EditorComponent', - alias: 'widget.SystemNoticeEditorComponent', - navigationClass: 'PartKeepr.SystemNoticeGrid', - editorClass: 'PartKeepr.SystemNoticeEditor', - newItemText: i18n("New System Notice"), - model: 'PartKeepr.SystemNotice', - initComponent: function () { - this.createStore({ - sorters: [{ - property: 'date', - direction:'DESC' - }] - }); - - this.callParent(); - } -});- \ No newline at end of file + extend: 'PartKeepr.EditorComponent', + alias: 'widget.SystemNoticeEditorComponent', + navigationClass: 'PartKeepr.SystemNoticeGrid', + editorClass: 'PartKeepr.SystemNoticeEditor', + newItemText: i18n("New System Notice"), + model: 'PartKeepr.CoreBundle.Entity.SystemNotice', + initComponent: function () + { + this.createStore({ + sorters: [ + { + property: 'date', + direction: 'DESC' + } + ] + }); + + this.callParent(); + } +}); diff --git a/src/backend/PartKeepr/PartDistributor/PartDistributorManager.php b/src/backend/PartKeepr/PartDistributor/PartDistributorManager.php @@ -1,74 +0,0 @@ -<?php -namespace PartKeepr\PartDistributor; - -use PartKeepr\Util\Singleton, - PartKeepr\ManufacturerBundle\Entity\Manufacturer, - PartKeepr\PartKeepr, - PartKeepr\Manufacturer\Exceptions\ManufacturerNotFoundException; - -class PartDistributorManager extends Singleton { - public function getPartDistributors ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("pd.orderNumber, part.id AS part_id, dist.id AS distributor_id")->from("PartKeepr\Part\PartDistributor","pd") - ->leftJoin('pd.distributor', "dist") - ->leftJoin("pd.part", "part"); - - /*if ($filter != "") { - $manufacturer = Manufacturer::loadById($filter); - $qb = $qb->where("st.manufacturer = :manufacturer"); - $qb->setParameter("manufacturer", $manufacturer); - }*/ - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("pd.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(pd.id)")->from("PartKeepr\Part\PartDistributor","pd"); - - - /* - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("st.manufacturer = :manufacturer"); - $totalQueryBuilder->setParameter("manufacturer", $manufacturer); - }*/ - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - public function getPartDistributor ($id) { - $partDistributor = PartKeepr::getEM()->find("PartKeepr\Part\PartDistributor", $id); - - if ($partDistributor) { - return $partDistributor; - } else { - throw new PartDistributorNotFoundException(); - } - } - - public function addPartDistributor ($orderNumber) { - $partDistributor = new PartDistributor(); - $partDistributor->setName($orderNumber); - - PartKeepr::getEM()->persist($partDistributor); - PartKeepr::getEM()->flush(); - - return $partDistributor; - } - public function deletePartDistributor ($id) { - $manufacturer = $this->getManufacturer($id); - - PartKeepr::getEM()->remove($manufacturer); - PartKeepr::getEM()->flush(); - } -}- \ No newline at end of file diff --git a/src/backend/PartKeepr/PartDistributor/PartDistributorService.php b/src/backend/PartKeepr/PartDistributor/PartDistributorService.php @@ -1,84 +0,0 @@ -<?php -namespace PartKeepr\ManufacturerICLogo; - -use PartKeepr\ManufacturerBundle\Entity\ManufacturerICLogo, - PartKeepr\Service\RestfulService, - PartKeepr\Service\Service, - PartKeepr\PartKeepr, - PartKeepr\ManufacturerBundle\Entity\Manufacturer, - PartKeepr\Session\SessionManager; - -class PartDistributorService extends Service implements RestfulService { - public function get () { - if ($this->hasParameter("id")) { - return PartDistributorManager::getInstance()->getManufacturerICLogo($this->getParameter("id"))->serialize(); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "id", - "direction" => "ASC"); - } - - $filter = ""; - - if ($this->hasParameter("filter")) { - $tmp = json_decode($this->getParameter("filter"), true); - - foreach ($tmp as $item) { - if (array_key_exists("property", $item)) { - if ($item["property"] == "manufacturer_id") { - if (array_key_exists("value", $item)) { - $filter = $item["value"]; - } - } - } - } - } - // @todo This seems wrong?!? - return ManufacturerICLogoManager::getInstance()->getManufacturerICLogos( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $filter); - } - } - - public function create () { - $this->requireParameter("tmp_id"); - $this->requireParameter("manufacturer_id"); - - $tmpImage = TempImage::loadById($this->getParameter("tmp_id")); - - $image = new ManufacturerICLogo(); - - $manufacturer = Manufacturer::loadById($this->getParameter("manufacturer_id")); - - $image->setManufacturer($manufacturer); - $image->replace($tmpImage->getFilename()); - PartKeepr::getEM()->persist($image); - PartKeepr::getEM()->flush(); - - return $image->serialize(); - } - - public function update () { - - } - - public function destroy () { - $this->requireParameter("id"); - - $logo = ManufacturerICLogo::loadById($this->getParameter("id")); - - PartKeepr::getEM()->remove($logo); - PartKeepr::getEM()->flush(); - - return array("data" => null); - } - -}- \ No newline at end of file diff --git a/src/backend/PartKeepr/PartKeepr.php b/src/backend/PartKeepr/PartKeepr.php @@ -2,307 +2,302 @@ namespace PartKeepr; use Doctrine\ORM\EntityManager; -use PartKeepr\SystemNotice\SystemNoticeManager; use PartKeepr\Util\Configuration as PartKeeprConfiguration; -class PartKeepr { - /** - * Initializes the PartKeepr system - * - * You *need* to call this method before doing anything else. - * - * An environment is used to load a different configuration file. - * Usually, you don't need to pass anything here. - * - * @param $environment string The environment to use, null otherwise. - */ - public static function initialize ($environment = null) { - self::initializeConfig($environment); - } - - /** - * Returns an array of all cronjobs which are required for proper execution of PartKeepr. - * - * @return Array The filenames of each cronjob which is required - */ - public static function getRequiredCronjobs () { - return array( - "CreateStatisticSnapshot.php", - "UpdatePartCacheData.php", - "UpdateTipsOfTheDay.php", - "CheckForUpdates.php" - ); - } - - /** - * Initializes the configuration for a given environment. - * - * An environment is used to load a different configuration file. - * - * Usually, you don't need to pass anything here. - * - * - * @param $environment string The environment to use, null otherwise. - */ - public static function initializeConfig ($environment = null) { - if ($environment != null) { - $config = self::getRootDirectory()."/config-$environment.php"; - } else { - $config = self::getRootDirectory()."/config.php"; - } - - if (file_exists($config)) { - include($config); - } - - // Check if the files path is set. If not, fall back to <partkeepr-root>/data/ - if (PartKeeprConfiguration::getOption("partkeepr.files.path", null) === null) { - - PartKeeprConfiguration::setOption("partkeepr.files.path", - PartKeepr::getRootDirectory() . "/data/"); - } - - // Check if the image path is set. If not, fall back to <configured-files-directory>/images/ - if (PartKeeprConfiguration::getOption("partkeepr.images.path", null) === null) { - - PartKeeprConfiguration::setOption("partkeepr.images.path", - PartKeeprConfiguration::getOption("partkeepr.files.path") . "images/"); - } - - // Check if the image cache path is set. If not, fall back to <configured-images-directory>/images/ - if (PartKeeprConfiguration::getOption("partkeepr.images.cache", null) === null) { - - PartKeeprConfiguration::setOption("partkeepr.images.cache", - PartKeeprConfiguration::getOption("partkeepr.images.path") . "cache/"); - - } - - } - - /** - * Checks against the versions at partkeepr.org. - * - * If a newer version was found, create a system notice entry. - */ - public static function doVersionCheck () { - - $data = file_get_contents("http://www.partkeepr.org/versions.json"); - $versions = json_decode($data, true); - - if (PartKeeprVersion::PARTKEEPR_VERSION == "{V_GIT}") { return; } - if (substr(PartKeeprVersion::PARTKEEPR_VERSION,0,17) == "partkeepr-nightly") { return; } - - if (version_compare(PartKeepr::getVersion(), $versions[0]["version"], '<')) { - - SystemNoticeManager::getInstance()->createUniqueSystemNotice( - "PARTKEEPR_VERSION_".$versions[0]["version"], - sprintf(PartKeepr::i18n("New PartKeepr Version %s available"), $versions[0]["version"]), - sprintf(PartKeepr::i18n("PartKeepr Version %s changelog:"), $versions[0]["version"]) . "\n\n". - $versions[0]["changelog"] - ); - - } - } - - /** - * Returns the EntityManager. Shortcut for getEntityManager(). - * @return EntityManager The EntityManager - */ - public static function getEM () { - return self::getEntityManager(); - } - - public static function getRootDirectory () { - return dirname(dirname(dirname(__DIR__))); - } - - /** - * Returns the EntityManager. - * @return EntityManager The EntityManager - */ - public static function getEntityManager () { +class PartKeepr +{ + /** + * Initializes the PartKeepr system + * + * You *need* to call this method before doing anything else. + * + * An environment is used to load a different configuration file. + * Usually, you don't need to pass anything here. + * + * @param $environment string The environment to use, null otherwise. + */ + public static function initialize($environment = null) + { + self::initializeConfig($environment); + } + + /** + * Returns an array of all cronjobs which are required for proper execution of PartKeepr. + * + * @return Array The filenames of each cronjob which is required + */ + public static function getRequiredCronjobs() + { + return array( + "CreateStatisticSnapshot.php", + "UpdatePartCacheData.php", + "UpdateTipsOfTheDay.php", + "CheckForUpdates.php", + ); + } + + /** + * Initializes the configuration for a given environment. + * + * An environment is used to load a different configuration file. + * + * Usually, you don't need to pass anything here. + * + * + * @param $environment string The environment to use, null otherwise. + */ + public static function initializeConfig($environment = null) + { + if ($environment != null) { + $config = self::getRootDirectory()."/config-$environment.php"; + } else { + $config = self::getRootDirectory()."/config.php"; + } + + if (file_exists($config)) { + include($config); + } + + // Check if the files path is set. If not, fall back to <partkeepr-root>/data/ + if (PartKeeprConfiguration::getOption("partkeepr.files.path", null) === null) { + + PartKeeprConfiguration::setOption("partkeepr.files.path", + PartKeepr::getRootDirectory()."/data/"); + } + + // Check if the image path is set. If not, fall back to <configured-files-directory>/images/ + if (PartKeeprConfiguration::getOption("partkeepr.images.path", null) === null) { + + PartKeeprConfiguration::setOption("partkeepr.images.path", + PartKeeprConfiguration::getOption("partkeepr.files.path")."images/"); + } + + // Check if the image cache path is set. If not, fall back to <configured-images-directory>/images/ + if (PartKeeprConfiguration::getOption("partkeepr.images.cache", null) === null) { + + PartKeeprConfiguration::setOption("partkeepr.images.cache", + PartKeeprConfiguration::getOption("partkeepr.images.path")."cache/"); + + } + + } + + /** + * Returns the EntityManager. Shortcut for getEntityManager(). + * + * @return EntityManager The EntityManager + */ + public static function getEM() + { + return self::getEntityManager(); + } + + public static function getRootDirectory() + { + return dirname(dirname(dirname(__DIR__))); + } + + /** + * Returns the EntityManager. + * + * @return EntityManager The EntityManager + */ + public static function getEntityManager() + { $container = \AppKernel::getMigrationContainer(); + return $container->get('doctrine')->getManager(); - } - - /** - * Returns the class metadata for all entity classes - * @return array an array of class metadata objects - */ - public static function getClassMetaData () { - $classes = self::getEntityClasses(); - - $aClasses = array(); - - foreach ($classes as $class) { - $aClasses[] = PartKeepr::getEM()->getClassMetadata($class); - } - - return $aClasses; - } - - /** - * Returns a list of all classes we use for entities. - * @return array An array of strings with all class names - */ - public static function getEntityClasses () { - return array( - 'PartKeepr\AuthBundle\Entity\User', - 'PartKeepr\Session\Session', - - 'PartKeepr\EventNotification\Event', - 'PartKeepr\EventNotification\LastNotification', - - 'PartKeepr\Footprint\Footprint', - 'PartKeepr\Footprint\FootprintImage', - 'PartKeepr\Footprint\FootprintAttachment', - 'PartKeepr\FootprintBundle\Entity\FootprintCategory', - - 'PartKeepr\PartBundle\Entity\Part', - 'PartKeepr\PartBundle\Entity\PartUnit', - 'PartKeepr\PartBundle\Entity\PartManufacturer', - 'PartKeepr\PartBundle\Entity\PartDistributor', - 'PartKeepr\PartBundle\Entity\PartImage', - 'PartKeepr\PartBundle\Entity\PartAttachment', - 'PartKeepr\PartBundle\Entity\PartCategory', - - 'PartKeepr\Printing\PageBasicLayout\PageBasicLayout', - 'PartKeepr\Printing\PrintingJob\PrintingJob', - 'PartKeepr\Printing\PrintingJobConfiguration\PrintingJobConfiguration', - - 'PartKeepr\Project\Project', - 'PartKeepr\Project\ProjectPart', - 'PartKeepr\Project\ProjectAttachment', - - 'PartKeepr\StorageLocationBundle\Entity\StorageLocation', - 'PartKeepr\StorageLocationBundle\Entity\StorageLocationImage', - - 'PartKeepr\Stock\StockEntry', - - 'PartKeepr\ManufacturerBundle\Entity\Manufacturer', - 'PartKeepr\ManufacturerBundle\Entity\ManufacturerICLogo', - - 'PartKeepr\DistributorBundle\Entity\Distributor', - - 'PartKeepr\ImageBundle\Entity\Image', - 'PartKeepr\ImageBundle\Entity\CachedImage', - 'PartKeepr\ImageBundle\Entity\TempImage', - - 'PartKeepr\UploadedFileBundle\Entity\TempUploadedFile', - - 'PartKeepr\Statistic\StatisticSnapshot', - 'PartKeepr\Statistic\StatisticSnapshotUnit', - 'PartKeepr\SiPrefixBundle\Entity\SiPrefix', - 'PartKeepr\Unit\Unit', - 'PartKeepr\PartBundle\Entity\PartParameter', - - 'PartKeepr\TipOfTheDayBundle\Entity\TipOfTheDay', - 'PartKeepr\TipOfTheDayBundle\Entity\TipOfTheDayHistory', - 'PartKeepr\AuthBundle\Entity\UserPreference', - 'PartKeepr\SystemNotice\SystemNotice', - 'PartKeepr\CronLogger\CronLogger' - - ); - } - - /** - * Formats a message and applies internationalization. - * - * This method accepts sprintf-like parameters, which are appended after the $string parameter. - * - * @param $string string The string to internationalize - * @todo stub - */ - public static function i18n ($string) { - if (func_num_args() > 1) { - $args = func_get_args(); - array_shift($args); - - return vsprintf($string, $args); - } else { - return $string; - } - } - - /** - * Returns a new GUID. - * @return string The new GUID - */ - public static function createGUIDv4() { - return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', - - // 32 bits for "time_low" - mt_rand(0, 0xffff), mt_rand(0, 0xffff), - - // 16 bits for "time_mid" - mt_rand(0, 0xffff), - - // 16 bits for "time_hi_and_version", - // four most significant bits holds version number 4 - mt_rand(0, 0x0fff) | 0x4000, - - // 16 bits, 8 bits for "clk_seq_hi_res", - // 8 bits for "clk_seq_low", - // two most significant bits holds zero and one for variant DCE1.1 - mt_rand(0, 0x3fff) | 0x8000, - - // 48 bits for "node" - mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) - ); - } - - /** - * Returns the current PartKeepr version. - * @return string The PartKeepr Version - */ - public static function getVersion () { - if (PartKeeprVersion::PARTKEEPR_VERSION == "{V_GIT}") { - return "GIT development version"; - } - return PartKeeprVersion::PARTKEEPR_VERSION; - } - - /** - * This is a re-implementation of gettype(). - * - * The PHP documentation states that the "gettype" return values will change in the future, so we need - * to make sure we don't get bitten by the change. - * - * @param mixed $var - * @return string The type - */ - public static function getType($var) - { - if (is_array($var)) return "array"; - if (is_bool($var)) return "boolean"; - if (is_float($var)) return "float"; - if (is_int($var)) return "integer"; - if (is_null($var)) return "NULL"; - if (is_numeric($var)) return "numeric"; - if (is_object($var)) return "object"; - if (is_resource($var)) return "resource"; - if (is_string($var)) return "string"; - return "unknown type"; - } - - /** - * Returns the effective size from a human-readable byte format. - * - * Example: - * getBytesFromHumanReadable("1M") will return 1048576. - * - * @param string $size_str The byte - * @return int The bytes - */ - public static function getBytesFromHumanReadable ($size_str) - { - switch (substr ($size_str, -1)) - { - case 'M': case 'm': return (int)$size_str * 1048576; - case 'K': case 'k': return (int)$size_str * 1024; - case 'G': case 'g': return (int)$size_str * 1073741824; - default: return $size_str; - } - } + } + + /** + * Returns the class metadata for all entity classes + * + * @return array an array of class metadata objects + */ + public static function getClassMetaData() + { + $classes = self::getEntityClasses(); + + $aClasses = array(); + + foreach ($classes as $class) { + $aClasses[] = PartKeepr::getEM()->getClassMetadata($class); + } + + return $aClasses; + } + + /** + * Returns a list of all classes we use for entities. + * + * @return array An array of strings with all class names + */ + public static function getEntityClasses() + { + return array( + 'PartKeepr\AuthBundle\Entity\User', + 'PartKeepr\Session\Session', + 'PartKeepr\EventNotification\Event', + 'PartKeepr\EventNotification\LastNotification', + 'PartKeepr\Footprint\Footprint', + 'PartKeepr\Footprint\FootprintImage', + 'PartKeepr\Footprint\FootprintAttachment', + 'PartKeepr\FootprintBundle\Entity\FootprintCategory', + 'PartKeepr\PartBundle\Entity\Part', + 'PartKeepr\PartBundle\Entity\PartUnit', + 'PartKeepr\PartBundle\Entity\PartManufacturer', + 'PartKeepr\PartBundle\Entity\PartDistributor', + 'PartKeepr\PartBundle\Entity\PartImage', + 'PartKeepr\PartBundle\Entity\PartAttachment', + 'PartKeepr\PartBundle\Entity\PartCategory', + 'PartKeepr\Printing\PageBasicLayout\PageBasicLayout', + 'PartKeepr\Printing\PrintingJob\PrintingJob', + 'PartKeepr\Printing\PrintingJobConfiguration\PrintingJobConfiguration', + 'PartKeepr\Project\Project', + 'PartKeepr\Project\ProjectPart', + 'PartKeepr\Project\ProjectAttachment', + 'PartKeepr\StorageLocationBundle\Entity\StorageLocation', + 'PartKeepr\StorageLocationBundle\Entity\StorageLocationImage', + 'PartKeepr\Stock\StockEntry', + 'PartKeepr\ManufacturerBundle\Entity\Manufacturer', + 'PartKeepr\ManufacturerBundle\Entity\ManufacturerICLogo', + 'PartKeepr\DistributorBundle\Entity\Distributor', + 'PartKeepr\ImageBundle\Entity\Image', + 'PartKeepr\ImageBundle\Entity\CachedImage', + 'PartKeepr\ImageBundle\Entity\TempImage', + 'PartKeepr\UploadedFileBundle\Entity\TempUploadedFile', + 'PartKeepr\Statistic\StatisticSnapshot', + 'PartKeepr\Statistic\StatisticSnapshotUnit', + 'PartKeepr\SiPrefixBundle\Entity\SiPrefix', + 'PartKeepr\Unit\Unit', + 'PartKeepr\PartBundle\Entity\PartParameter', + 'PartKeepr\TipOfTheDayBundle\Entity\TipOfTheDay', + 'PartKeepr\TipOfTheDayBundle\Entity\TipOfTheDayHistory', + 'PartKeepr\AuthBundle\Entity\UserPreference', + 'PartKeepr\CoreBundle\Entity\SystemNotice', + 'PartKeepr\CronLogger\CronLogger', + + ); + } + + /** + * Formats a message and applies internationalization. + * + * This method accepts sprintf-like parameters, which are appended after the $string parameter. + * + * @param $string string The string to internationalize + * + * @todo stub + */ + public static function i18n($string) + { + if (func_num_args() > 1) { + $args = func_get_args(); + array_shift($args); + + return vsprintf($string, $args); + } else { + return $string; + } + } + + /** + * Returns a new GUID. + * + * @return string The new GUID + */ + public static function createGUIDv4() + { + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + + // 32 bits for "time_low" + mt_rand(0, 0xffff), mt_rand(0, 0xffff), + + // 16 bits for "time_mid" + mt_rand(0, 0xffff), + + // 16 bits for "time_hi_and_version", + // four most significant bits holds version number 4 + mt_rand(0, 0x0fff) | 0x4000, + + // 16 bits, 8 bits for "clk_seq_hi_res", + // 8 bits for "clk_seq_low", + // two most significant bits holds zero and one for variant DCE1.1 + mt_rand(0, 0x3fff) | 0x8000, + + // 48 bits for "node" + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) + ); + } + + /** + * This is a re-implementation of gettype(). + * + * The PHP documentation states that the "gettype" return values will change in the future, so we need + * to make sure we don't get bitten by the change. + * + * @param mixed $var + * + * @return string The type + */ + public static function getType($var) + { + if (is_array($var)) { + return "array"; + } + if (is_bool($var)) { + return "boolean"; + } + if (is_float($var)) { + return "float"; + } + if (is_int($var)) { + return "integer"; + } + if (is_null($var)) { + return "NULL"; + } + if (is_numeric($var)) { + return "numeric"; + } + if (is_object($var)) { + return "object"; + } + if (is_resource($var)) { + return "resource"; + } + if (is_string($var)) { + return "string"; + } + + return "unknown type"; + } + + /** + * Returns the effective size from a human-readable byte format. + * + * Example: + * getBytesFromHumanReadable("1M") will return 1048576. + * + * @param string $size_str The byte + * + * @return int The bytes + */ + public static function getBytesFromHumanReadable($size_str) + { + switch (substr($size_str, -1)) { + case 'M': + case 'm': + return (int)$size_str * 1048576; + case 'K': + case 'k': + return (int)$size_str * 1024; + case 'G': + case 'g': + return (int)$size_str * 1073741824; + default: + return $size_str; + } + } } diff --git a/src/backend/PartKeepr/PartKeeprVersion.php b/src/backend/PartKeepr/PartKeeprVersion.php @@ -1,15 +0,0 @@ -<?php -namespace PartKeepr; - -class PartKeeprVersion { - /** - * Holds the PartKeepr Version. - * - * If {V_GIT}, then the function will return 'GIT Development Version'. - * {V_GIT} will be replaced by the build script with the actual version. - * - * The reason why we have a separate class for the version constant is that - * we can easily replace it from scripts. - */ - const PARTKEEPR_VERSION = '{V_GIT}'; -}- \ No newline at end of file diff --git a/src/backend/PartKeepr/SystemNotice/SystemNotice.php b/src/backend/PartKeepr/SystemNotice/SystemNotice.php @@ -1,142 +0,0 @@ -<?php -namespace PartKeepr\SystemNotice; - -use PartKeepr\UploadedFileBundle\Entity\UploadedFile, - PartKeepr\Util\BaseEntity, - PartKeepr\Util\Serializable, - PartKeepr\Util\Deserializable, - Doctrine\ORM\Mapping as ORM; - -/** - * Holds a system notice - * @ORM\Entity - **/ -class SystemNotice extends BaseEntity implements Serializable { - /** - * @ORM\Column(type="datetime") - * @var \DateTime - */ - private $date; - - /** - * @ORM\Column(type="string") - * @var string - */ - private $title; - - /** - * The description of this attachment - * @ORM\Column(type="text") - * @var string - */ - private $description; - - /** - * Defines if the system notice has been acknowledged - * @ORM\Column(type="boolean") - * @var boolean - */ - private $acknowledged = false; - - /** - * Specifies the type. This is required for unique notices which shouldn't pop up every time we create them. - * @ORM\Column(type="string") - * @var string - */ - private $type; - - /** - * Sets the date and time for this entry - * @param \DateTime $date The date and time - */ - public function setDate (\DateTime $date) { - $this->date = $date; - } - - /** - * Returns the date and time for this entry - * - * @return \DateTime the date and time for this entry - */ - public function getDate () { - return $this->date; - } - - /** - * Sets the title for this entry - * @param string $title the title for this entry - */ - public function setTitle ($title) { - $this->title = $title; - } - - /** - * Returns the title for this entry - * @return string the title - */ - public function getTitle () { - return $this->title; - } - - /** - * Sets the description - * @param string $description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * Sets the value of the acknowledged flag - * @param boolean $bAck True if the notice should be acknowledged (default), false otherwise - */ - public function setAcknowledgedFlag ($bAck = true) { - $this->acknowledged = $bAck; - } - - /** - * Returns the value of the acknowledged flag - * - * @return boolean true if this notice has been acknowledged, false otherwise - */ - public function getAcknowledgedFlag () { - return $this->acknowledged; - } - - /** - * Sets the type of this entry - * @param string $type - */ - public function setType ($type) { - $this->type = $type; - } - - /** - * Returns the type of this entry - * @return string The type - */ - public function getType () { - return $this->type; - } - - /** - * Serializes this system notice attachment - * @return array The serialized system notice - */ - public function serialize () { - return array( - "id" => $this->getId(), - "date" => $this->getDate()->format("Y-m-d H:i:s"), - "title" => $this->getTitle(), - "description" => $this->getDescription(), - "acknowledged" => $this->getAcknowledgedFlag()); - } -}- \ No newline at end of file diff --git a/src/backend/PartKeepr/SystemNotice/SystemNoticeManager.php b/src/backend/PartKeepr/SystemNotice/SystemNoticeManager.php @@ -1,55 +0,0 @@ -<?php -namespace PartKeepr\SystemNotice; - -use PartKeepr\Manager\AbstractManager, - PartKeepr\Project\Project, - PartKeepr\PartKeepr; - -class SystemNoticeManager extends AbstractManager { - /** - * Returns the FQCN for the target entity to operate on. - * @return string The FQCN, e.g. PartKeepr\Part - */ - public function getEntityName () { - return 'PartKeepr\SystemNotice\SystemNotice'; - } - - /** - * Returns all fields which need to appear in the getList ResultSet. - * @return array An array of all fields which should be returned - */ - public function getQueryFields () { - return array("id", "title", "date"); - } - - /** - * Returns the default sort field - * - * @return string The default sort field - */ - public function getDefaultSortField () { - return "date"; - } - - public function createUniqueSystemNotice ($type, $title, $description) { - $dql = "SELECT sn FROM PartKeepr\SystemNotice\SystemNotice sn WHERE sn.type = :type"; - $query = PartKeepr::getEM()->createQuery($dql); - - $query->setParameter("type", $type, \PDO::PARAM_BOOL); - - try { - $notice = $query->getSingleResult(); - } catch (\Exception $e) { - $notice = new SystemNotice(); - PartKeepr::getEM()->persist($notice); - } - - $notice->setDate(new \DateTime()); - $notice->setTitle($title); - $notice->setDescription($description); - $notice->setType($type); - - PartKeepr::getEM()->flush(); - - } -}- \ No newline at end of file diff --git a/src/backend/PartKeepr/SystemNotice/SystemNoticeService.php b/src/backend/PartKeepr/SystemNotice/SystemNoticeService.php @@ -1,83 +0,0 @@ -<?php -namespace PartKeepr\SystemNotice; - -use PartKeepr\Service\RestfulService, - PartKeepr\Service\Service, - PartKeepr\PartKeepr, - PartKeepr\Manager\ManagerFilter; - -class SystemNoticeService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return array("data" => SystemNoticeManager::getInstance()->getEntity($this->getParameter("id"))->serialize()); - } else { - $parameters = new ManagerFilter($this); - $parameters->setFilterCallback(array($this, "filterCallback")); - - return SystemNoticeManager::getInstance()->getList($parameters); - } - } - - public function filterCallback ($queryBuilder) { - $queryBuilder->andWhere("q.acknowledged = :acknowledged"); - $queryBuilder->setParameter("acknowledged", false, \PDO::PARAM_BOOL); - } - /** - * Stub method to fulfill the RestfulService. We don't want to have SystemNotices created by the user, so - * we bail out with an exception. - * - * (non-PHPdoc) - * @see PartKeepr\Service.RestfulService::create() - */ - public function create () { - throw new \Exception("Not implemented"); - } - - /** - * Stub method to fulfill the RestfulService. We don't want to have SystemNotices updated by the user, so - * we bail out with an exception. - * - * (non-PHPdoc) - * @see PartKeepr\Service.RestfulService::update() - */ - public function update () { - throw new \Exception("Not implemented"); - - } - - /** - * (non-PHPdoc) - * @see PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - SystemNoticeManager::getInstance()->deleteEntity($this->getParameter("id")); - - return array("data" => null); - } - - public function acknowledge () { - $this->requireParameter("id"); - - $entity = SystemNoticeManager::getInstance()->getEntity($this->getParameter("id")); - $entity->setAcknowledgedFlag(); - } - - public function hasUnacknowledgedNotices () { - $dql = "SELECT COUNT(c) FROM PartKeepr\SystemNotice\SystemNotice c WHERE c.acknowledged = :a"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("a", false, \PDO::PARAM_BOOL); - - $bRetval = false; - - if ($query->getSingleScalarResult() > 0) { - $bRetval = true; - } - return array("data" => array("unacknowledgedNotices" => $bRetval)); - } -}- \ No newline at end of file