partkeepr

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

commit 605531f57ea5e6a6f38a27ec86637be27fd835a8
parent 017f7f1f1b38a3e9ac7461d1feac85b9c4647161
Author: felicitus <felicitus@felicitus.org>
Date:   Sun, 24 Jun 2012 02:40:17 +0200

Merge branch 'master' of github.com:partkeepr/PartKeepr

Diffstat:
Mbuild.properties | 5+++--
Mbuild.xml | 16+++++++++-------
Mcli-config.php | 2+-
Mconfig-test.php | 4++--
Mconfig.php.template | 4++--
Mcronjobs/CheckForUpdates.php | 8++++----
Mcronjobs/CreateRSSFeed.php | 10+++++-----
Mcronjobs/CreateStatisticSnapshot.php | 10+++++-----
Mcronjobs/UpdatePartCacheData.php | 12++++++------
Mcronjobs/UpdateTipsOfTheDay.php | 10+++++-----
Mdoctrine.php | 6+++---
Mdocumentation/internals/NEW-RELEASE | 3+++
Mmigrations.yml | 4++--
Mscripts/UpdateCategoryPathCache.php | 12++++++------
Asrc/backend/PartKeepr/Auth/AuthService.php | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Category/AbstractCategory.php | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Category/AbstractCategoryManager.php | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Category/AbstractCategoryService.php | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Category/Exceptions/CategoryNotFoundException.php | 16++++++++++++++++
Asrc/backend/PartKeepr/CronLogger/CronLogger.php | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/CronLogger/CronLoggerManager.php | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Distributor/Distributor.php | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Distributor/DistributorManager.php | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Distributor/DistributorService.php | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Footprint/Footprint.php | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Footprint/FootprintAttachment.php | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Footprint/FootprintImage.php | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Footprint/FootprintManager.php | 158+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Footprint/FootprintService.php | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/FootprintAttachment/FootprintAttachmentManager.php | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/FootprintAttachment/FootprintAttachmentService.php | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/FootprintCategory/FootprintCategory.php | 15+++++++++++++++
Asrc/backend/PartKeepr/FootprintCategory/FootprintCategoryManager.php | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/FootprintCategory/FootprintCategoryService.php | 10++++++++++
Asrc/backend/PartKeepr/FulltextSearch/FulltextSearch.php | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Image/CachedImage.php | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Image/Exceptions/InvalidImageTypeException.php | 12++++++++++++
Asrc/backend/PartKeepr/Image/Image.php | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Image/ImageRenderer.php | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Image/RenderableImage.php | 17+++++++++++++++++
Asrc/backend/PartKeepr/Logger/Logger.php | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manager/AbstractManager.php | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manager/Exceptions/EntityInUseException.php | 32++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manager/ManagerFilter.php | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manager/Sorter.php | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manufacturer/Manufacturer.php | 251+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manufacturer/ManufacturerICLogo.php | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manufacturer/ManufacturerManager.php | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Manufacturer/ManufacturerService.php | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/ManufacturerICLogo/ManufacturerICLogoManager.php | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/ManufacturerICLogo/ManufacturerICLogoService.php | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/Exceptions/CategoryNotAssignedException.php | 21+++++++++++++++++++++
Asrc/backend/PartKeepr/Part/Exceptions/StorageLocationNotAssignedException.php | 20++++++++++++++++++++
Asrc/backend/PartKeepr/Part/Part.php | 640+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartAttachment.php | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartDistributor.php | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartFulltextSearch.php | 29+++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartImage.php | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartManager.php | 442+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartManufacturer.php | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartService.php | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Part/PartUnit.php | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartCategory/PartCategory.php | 15+++++++++++++++
Asrc/backend/PartKeepr/PartCategory/PartCategoryManager.php | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartCategory/PartCategoryService.php | 10++++++++++
Asrc/backend/PartKeepr/PartDistributor/PartDistributorManager.php | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartDistributor/PartDistributorService.php | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartKeepr.php | 435+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartKeeprVersion.php | 16++++++++++++++++
Asrc/backend/PartKeepr/PartParameter/PartParameter.php | 247+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartUnit/PartUnitManager.php | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/PartUnit/PartUnitService.php | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Ping/PingService.php | 20++++++++++++++++++++
Asrc/backend/PartKeepr/Project/Project.php | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Project/ProjectAttachment.php | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Project/ProjectManager.php | 34++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Project/ProjectPart.php | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Project/ProjectService.php | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/ProjectAttachment/ProjectAttachmentManager.php | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/ProjectAttachment/ProjectAttachmentService.php | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/ProjectReport/ProjectReportService.php | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/REST/ApplicationController.php | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/REST/Model.php | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/REST/Request.php | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/REST/Response.php | 21+++++++++++++++++++++
Asrc/backend/PartKeepr/Service/AdminService.php | 14++++++++++++++
Asrc/backend/PartKeepr/Service/AnonService.php | 6++++++
Asrc/backend/PartKeepr/Service/Exceptions/ServiceException.php | 6++++++
Asrc/backend/PartKeepr/Service/RestfulService.php | 10++++++++++
Asrc/backend/PartKeepr/Service/Service.php | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Service/ServiceManager.php | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Session/Exceptions/SessionNotFoundException.php | 11+++++++++++
Asrc/backend/PartKeepr/Session/Session.php | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Session/SessionManager.php | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/AbstractSetup.php | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/ConfigFileSetup.php | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/FootprintSetup.php | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/ManufacturerSetup.php | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Migration/PartDB/DistributorMigration.php | 34++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Migration/PartDB/FootprintMigration.php | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Migration/PartDB/PartCategoryMigration.php | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Migration/PartDB/PartDBMigration.php | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Migration/PartDB/PartMigration.php | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Migration/PartDB/StorageLocationMigration.php | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/MiscSettingsSetup.php | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/PartCategorySetup.php | 28++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/PartUnitSetup.php | 36++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/SchemaSetup.php | 35+++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/Setup.php | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/SiPrefixSetup.php | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/UnitSetup.php | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Setup/UserSetup.php | 32++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/SiPrefix/SiPrefix.php | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/SiPrefix/SiPrefixManager.php | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/SiPrefix/SiPrefixService.php | 27+++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Statistic/StatisticService.php | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Statistic/StatisticSnapshot.php | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Statistic/StatisticSnapshotManager.php | 39+++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Statistic/StatisticSnapshotUnit.php | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Stock/StockEntry.php | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Stock/StockManager.php | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Stock/StockService.php | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/StorageLocation/Exceptions/StorageLocationNotFoundException.php | 13+++++++++++++
Asrc/backend/PartKeepr/StorageLocation/StorageLocation.php | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/StorageLocation/StorageLocationImage.php | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/StorageLocation/StorageLocationManager.php | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/StorageLocation/StorageLocationService.php | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/System/SystemInformationRecord.php | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/System/SystemService.php | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/SystemNotice/SystemNotice.php | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/SystemNotice/SystemNoticeManager.php | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/SystemNotice/SystemNoticeService.php | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/TempFile/TempFileService.php | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/TempImage/TempImage.php | 20++++++++++++++++++++
Asrc/backend/PartKeepr/TempImage/TempImageService.php | 31+++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/TipOfTheDay/TipOfTheDay.php | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/TipOfTheDay/TipOfTheDayHistory.php | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/TipOfTheDay/TipOfTheDayService.php | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Unit/Unit.php | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Unit/UnitManager.php | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Unit/UnitService.php | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/UploadedFile/TempUploadedFile.php | 15+++++++++++++++
Asrc/backend/PartKeepr/UploadedFile/UploadedFile.php | 301+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/User/Exceptions/InvalidLoginDataException.php | 15+++++++++++++++
Asrc/backend/PartKeepr/User/Exceptions/UserAlreadyExistsException.php | 20++++++++++++++++++++
Asrc/backend/PartKeepr/User/Exceptions/UserDoesNotExistException.php | 18++++++++++++++++++
Asrc/backend/PartKeepr/User/User.php | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/User/UserManager.php | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/User/UserService.php | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/UserPreference/Exceptions/UserPreferenceNotFoundException.php | 21+++++++++++++++++++++
Asrc/backend/PartKeepr/UserPreference/UserPreference.php | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/UserPreference/UserPreferenceService.php | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Util/BaseEntity.php | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Util/Configuration.php | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Util/Deserializable.php | 11+++++++++++
Asrc/backend/PartKeepr/Util/Exceptions/EntityNotFoundException.php | 17+++++++++++++++++
Asrc/backend/PartKeepr/Util/Exceptions/EntityNotPersistantException.php | 14++++++++++++++
Asrc/backend/PartKeepr/Util/Exceptions/OutOfRangeException.php | 6++++++
Asrc/backend/PartKeepr/Util/OS/OperatingSystem.php | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Util/Serializable.php | 12++++++++++++
Asrc/backend/PartKeepr/Util/SerializableException.php | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/PartKeepr/Util/Singleton.php | 23+++++++++++++++++++++++
Asrc/backend/PartKeepr/Util/UtilService.php | 14++++++++++++++
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Auth/AuthService.php | 52----------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategory.php | 202-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategoryManager.php | 223-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategoryService.php | 145-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Category/Exceptions/CategoryNotFoundException.php | 16----------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/CronLogger/CronLogger.php | 59-----------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/CronLogger/CronLoggerManager.php | 87-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Distributor/Distributor.php | 232-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Distributor/DistributorManager.php | 108-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Distributor/DistributorService.php | 83-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php | 192-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintAttachment.php | 102-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintImage.php | 51---------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php | 158-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php | 96-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/FootprintAttachment/FootprintAttachmentManager.php | 69---------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/FootprintAttachment/FootprintAttachmentService.php | 103-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategory.php | 15---------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategoryManager.php | 43-------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategoryService.php | 10----------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/FulltextSearch/FulltextSearch.php | 95-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Image/CachedImage.php | 100-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Image/Exceptions/InvalidImageTypeException.php | 12------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Image/Image.php | 254-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Logger/Logger.php | 122-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manager/AbstractManager.php | 231-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manager/Exceptions/EntityInUseException.php | 32--------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manager/ManagerFilter.php | 197-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manager/Sorter.php | 80-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/Manufacturer.php | 251-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerICLogo.php | 64----------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerManager.php | 105-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerService.php | 83-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/ManufacturerICLogo/ManufacturerICLogoManager.php | 66------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/ManufacturerICLogo/ManufacturerICLogoService.php | 102-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/Exceptions/CategoryNotAssignedException.php | 21---------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/Exceptions/StorageLocationNotAssignedException.php | 20--------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/Part.php | 640-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartAttachment.php | 129-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartDistributor.php | 194-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartFulltextSearch.php | 30------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartImage.php | 51---------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartManager.php | 442-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartManufacturer.php | 107-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartService.php | 259-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Part/PartUnit.php | 138-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategory.php | 15---------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategoryManager.php | 43-------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategoryService.php | 10----------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartDistributor/PartDistributorManager.php | 75---------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartDistributor/PartDistributorService.php | 85-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php | 435-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartKeeprVersion.php | 16----------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartParameter/PartParameter.php | 247-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitManager.php | 107-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitService.php | 73-------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Ping/PingService.php | 20--------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Project/Project.php | 162-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectAttachment.php | 102-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectManager.php | 34----------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectPart.php | 137-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectService.php | 65-----------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/ProjectAttachment/ProjectAttachmentManager.php | 69---------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/ProjectAttachment/ProjectAttachmentService.php | 103-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/ProjectReport/ProjectReportService.php | 98-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/REST/ApplicationController.php | 42------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/REST/Model.php | 71-----------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/REST/Request.php | 115-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/REST/Response.php | 21---------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Service/AdminService.php | 14--------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Service/AnonService.php | 6------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Service/Exceptions/ServiceException.php | 6------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Service/RestfulService.php | 10----------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Service/Service.php | 110-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Service/ServiceManager.php | 127-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Session/Exceptions/SessionNotFoundException.php | 11-----------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Session/Session.php | 60------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Session/SessionManager.php | 69---------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/AbstractSetup.php | 45---------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/ConfigFileSetup.php | 66------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/FootprintSetup.php | 156-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/ManufacturerSetup.php | 56--------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/DistributorMigration.php | 34----------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/FootprintMigration.php | 43-------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartCategoryMigration.php | 50--------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartDBMigration.php | 71-----------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartMigration.php | 131-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/StorageLocationMigration.php | 51---------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/MiscSettingsSetup.php | 70----------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/PartCategorySetup.php | 28----------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/PartUnitSetup.php | 36------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/SchemaSetup.php | 35-----------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/Setup.php | 177-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/SiPrefixSetup.php | 47-----------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/UnitSetup.php | 62--------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Setup/UserSetup.php | 32--------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefix.php | 92-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefixManager.php | 43-------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefixService.php | 27---------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticService.php | 149-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshot.php | 110-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshotManager.php | 39---------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshotUnit.php | 96-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Stock/StockEntry.php | 239-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Stock/StockManager.php | 67-------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Stock/StockService.php | 94-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/Exceptions/StorageLocationNotFoundException.php | 13-------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocation.php | 106-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationImage.php | 51---------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationManager.php | 95-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationService.php | 109-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/System/SystemInformationRecord.php | 56--------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/System/SystemService.php | 100-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNotice.php | 142-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNoticeManager.php | 56--------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNoticeService.php | 84-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/TempFile/TempFileService.php | 73-------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/TempImage/TempImage.php | 20--------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/TempImage/TempImageService.php | 31-------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDay.php | 115-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDayHistory.php | 52----------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDayService.php | 87-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Unit/Unit.php | 131-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Unit/UnitManager.php | 100-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Unit/UnitService.php | 68--------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/UploadedFile/TempUploadedFile.php | 15---------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/UploadedFile/UploadedFile.php | 301-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/InvalidLoginDataException.php | 15---------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/UserAlreadyExistsException.php | 20--------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/UserDoesNotExistException.php | 18------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/User/User.php | 260-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/User/UserManager.php | 136-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/User/UserService.php | 102-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/UserPreference/Exceptions/UserPreferenceNotFoundException.php | 21---------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/UserPreference/UserPreference.php | 230-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/UserPreference/UserPreferenceService.php | 97-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/BaseEntity.php | 117-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Configuration.php | 93-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Deserializable.php | 11-----------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/EntityNotFoundException.php | 17-----------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/EntityNotPersistantException.php | 14--------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/OutOfRangeException.php | 6------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/OS/OperatingSystem.php | 94-------------------------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Serializable.php | 12------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/SerializableException.php | 60------------------------------------------------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/Singleton.php | 23-----------------------
Dsrc/backend/de/RaumZeitLabor/PartKeepr/Util/UtilService.php | 14--------------
Msrc/frontend/file.php | 24++++++++++++------------
Msrc/frontend/image.php | 52++++++++++++++++++++++------------------------------
Msrc/frontend/index.php | 18+++++++++---------
Msrc/frontend/js/Components/Part/Editor/PartDistributorGrid.js | 13++++++++++---
Msrc/frontend/js/Components/Part/PartDisplay.js | 22+++++++++++++++++-----
Asrc/frontend/js/Components/Part/PartImageDisplay.js | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/frontend/js/Components/Part/PartStockWindow.js | 31++++++++++++++++++++++++-------
Msrc/frontend/js/Models/PartAttachment.js | 1+
Msrc/frontend/js/Models/PartDistributor.js | 20++++++++++----------
Msrc/frontend/js/Util/i18n.js | 5+++++
Msrc/frontend/rest.php | 12++++++------
Msrc/frontend/rss.php | 8++++----
Msrc/frontend/service.php | 10+++++-----
Msrc/frontend/upload.php | 12++++++------
Msrc/setup/setup.php | 24++++++++++++------------
Msrc/setup/tests/check-database-connectivity.php | 36++++++++++++++++++------------------
Mtesting/PartTest.php | 32+++++++++++++++++++++++++++++---
Mtesting/Service.php | 2+-
Mtesting/SetupDatabase.php | 30+++++++++++++++---------------
Mtesting/genman.php | 2+-
Mtests/Auth/UserTest.php | 4++--
Mtests/Logger/LoggerTest.php | 6+++---
Mtests/Part/PartServiceTest.php | 42+++++++++++++++++++++---------------------
Mtests/Service/ServiceTest.php | 8++++----
Mtests/User/UserTest.php | 14+++++++-------
Mtests/UserPreference/UserPreferenceTest.php | 24++++++++++++------------
Mtests/Util/ConfigurationTest.php | 4++--
Mtests/bootstrap.php | 10+++++-----
Mutil/classes/ExtJSFile.php | 2++
339 files changed, 14361 insertions(+), 13993 deletions(-)

diff --git a/build.properties b/build.properties @@ -1,3 +1,4 @@ extjs.path=3rdparty/extjs packagepath=/tmp/partkeepr-pkg -source.php=src/backend/de/RaumZeitLabor/PartKeepr- \ No newline at end of file +source.php=src/backend/PartKeepr +build.fast=1+ \ No newline at end of file diff --git a/build.xml b/build.xml @@ -14,6 +14,8 @@ <target name="clean"> <delete dir="reports" /> <delete dir="frontend" /> + <delete dir="setup" /> + <delete file="partkeepr.jsb3" /> </target> <!-- Re-generates the proxies needed by Doctrine2 --> @@ -90,12 +92,12 @@ <else> <copy overwrite="true" todir="setup/js/wizard"> <fileset dir="3rdparty/ext-wizard/Ext.ux.Wizard"> - <include name="**"/> + <include name="**" /> </fileset> </copy> </else> </if> - + <echo>Copying src/setup</echo> <if> <isset property="build.fast" /> @@ -150,7 +152,7 @@ </if> <echo>Copying Ext Statusbar</echo> - <mkdir dir="frontend/js/Ext.ux/statusbar"/> + <mkdir dir="frontend/js/Ext.ux/statusbar" /> <if> <isset property="build.fast" /> <then> @@ -224,7 +226,7 @@ <phingcall target="build-setup" /> </target> - <!-- Fast build uses rsync instead of standard file copy --> + <!-- Fast build uses rsync instead of standard file copy --> <target name="build-fast"> <condition property="build.fast"> <or> @@ -236,7 +238,7 @@ <fail unless="build.fast" message="Fast build only supported on Mac and Unix-like systems (rsync required)" /> <phingcall target="build" /> - </target> + </target> <!-- Creates a new PartKeepr release. @@ -327,7 +329,7 @@ <exec executable="sed"> <arg value="-i" /> <arg value="s/{V_GIT}/${partkeepr.version}/g" /> - <arg value="${packagepath}/src/backend/de/RaumZeitLabor/PartKeepr/PartKeeprVersion.php" /> + <arg value="${packagepath}/src/backend/PartKeepr/PartKeeprVersion.php" /> </exec> </target> @@ -338,7 +340,7 @@ <format property="build.time" pattern="partkeepr-nightly-%Y%m%d" /> </tstamp> - <property name="partkeepr.version" value="{build.time}-nightly" /> + <property name="partkeepr.version" value="${build.time}" /> <phingcall target="set-version" /> <zip destfile="${build.time}.zip" basedir="${packagepath}" prefix="partkeepr-nightly/" /> diff --git a/cli-config.php b/cli-config.php @@ -1,5 +1,5 @@ <?php -use de\RaumZeitLabor\PartKeepr\PartKeepr; +use PartKeepr\PartKeepr; $helpers = array( 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper(PartKeepr::getEM()->getConnection()), diff --git a/config-test.php b/config-test.php @@ -1,7 +1,7 @@ <?php -namespace de\RaumZeitLabor\PartKeepr; +namespace PartKeepr; -use de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\Util\Configuration; Configuration::setOption("partkeepr.database.dbname", "partkeepr-test"); Configuration::setOption("partkeepr.database.driver", "pdo_sqlite"); diff --git a/config.php.template b/config.php.template @@ -1,7 +1,7 @@ <?php -namespace de\RaumZeitLabor\PartKeepr; +namespace PartKeepr; -use de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\Util\Configuration; /** * Specifies the username for the database diff --git a/cronjobs/CheckForUpdates.php b/cronjobs/CheckForUpdates.php @@ -6,12 +6,12 @@ * @author felicitus * */ -namespace de\RaumZeitLabor\PartKeepr\Cronjobs; +namespace PartKeepr\Cronjobs; -include(__DIR__."/../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include(__DIR__."/../src/backend/PartKeepr/PartKeepr.php"); -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\CronLogger\CronLoggerManager; +use PartKeepr\PartKeepr, + PartKeepr\CronLogger\CronLoggerManager; PartKeepr::initialize(); diff --git a/cronjobs/CreateRSSFeed.php b/cronjobs/CreateRSSFeed.php @@ -1,14 +1,14 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Cronjobs; +namespace PartKeepr\Cronjobs; -include(__DIR__."/../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include(__DIR__."/../src/backend/PartKeepr/PartKeepr.php"); -use de\RaumZeitLabor\PartKeepr\PartKeepr; -use de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\PartKeepr, + PartKeepr\Util\Configuration; PartKeepr::initialize(); -$dql = PartKeepr::getEM()->createQuery("SELECT p FROM de\RaumZeitLabor\PartKeepr\Part\Part p ORDER BY p.createDate DESC"); +$dql = PartKeepr::getEM()->createQuery("SELECT p FROM PartKeepr\Part\Part p ORDER BY p.createDate DESC"); $dql->setMaxResults(40); $parts = $dql->getResult(); diff --git a/cronjobs/CreateStatisticSnapshot.php b/cronjobs/CreateStatisticSnapshot.php @@ -1,11 +1,11 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Cronjobs; +namespace PartKeepr\Cronjobs; -include(__DIR__."/../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include(__DIR__."/../src/backend/PartKeepr/PartKeepr.php"); -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshotManager, - de\RaumZeitLabor\PartKeepr\CronLogger\CronLoggerManager; +use PartKeepr\PartKeepr, + PartKeepr\Statistic\StatisticSnapshotManager, + PartKeepr\CronLogger\CronLoggerManager; PartKeepr::initialize(); StatisticSnapshotManager::getInstance()->createSnapshot(); diff --git a/cronjobs/UpdatePartCacheData.php b/cronjobs/UpdatePartCacheData.php @@ -1,15 +1,15 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Cronjobs; +namespace PartKeepr\Cronjobs; -include(__DIR__."/../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include(__DIR__."/../src/backend/PartKeepr/PartKeepr.php"); -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshotManager, - de\RaumZeitLabor\PartKeepr\CronLogger\CronLoggerManager; +use PartKeepr\PartKeepr, + PartKeepr\Statistic\StatisticSnapshotManager, + PartKeepr\CronLogger\CronLoggerManager; PartKeepr::initialize(); -$query = PartKeepr::getEM()->createQuery("SELECT p FROM de\RaumZeitLabor\PartKeepr\Part\Part p"); +$query = PartKeepr::getEM()->createQuery("SELECT p FROM PartKeepr\Part\Part p"); $result = $query->getResult(); $fc = 0; diff --git a/cronjobs/UpdateTipsOfTheDay.php b/cronjobs/UpdateTipsOfTheDay.php @@ -8,13 +8,13 @@ * @author felicitus * */ -namespace de\RaumZeitLabor\PartKeepr\Cronjobs; +namespace PartKeepr\Cronjobs; -include(__DIR__."/../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include(__DIR__."/../src/backend/PartKeepr/PartKeepr.php"); -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDay, - de\RaumZeitLabor\PartKeepr\CronLogger\CronLoggerManager; +use PartKeepr\PartKeepr, + PartKeepr\TipOfTheDay\TipOfTheDay, + PartKeepr\CronLogger\CronLoggerManager; PartKeepr::initialize(); diff --git a/doctrine.php b/doctrine.php @@ -1,9 +1,9 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Foo; +namespace PartKeepr\Foo; -use de\RaumZeitLabor\PartKeepr\PartKeepr; +use PartKeepr\PartKeepr; -include("src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(""); // Variable $helperSet is defined inside cli-config.php diff --git a/documentation/internals/NEW-RELEASE b/documentation/internals/NEW-RELEASE @@ -30,3 +30,5 @@ The following steps describe how a new PartKeepr release is being built: * Write a blog entry * Push out notifications on twitter + +* Change irc topic to reflect the current version+ \ No newline at end of file diff --git a/migrations.yml b/migrations.yml @@ -2,4 +2,4 @@ name: PartKeepr migrations_namespace: DoctrineMigrations table_name: SchemaVersions -migrations_directory: src/backend/de/RaumZeitLabor/PartKeepr/Versions- \ No newline at end of file +migrations_directory: src/backend/PartKeepr/Versions+ \ No newline at end of file diff --git a/scripts/UpdateCategoryPathCache.php b/scripts/UpdateCategoryPathCache.php @@ -4,14 +4,14 @@ * * This script needs to be called after changing the partkeepr.category.path_separator. */ -namespace de\RaumZeitLabor\PartKeepr\Scripts; +namespace PartKeepr\Scripts; -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategoryManager; +use PartKeepr\PartKeepr, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Util\Configuration, + PartKeepr\FootprintCategory\FootprintCategoryManager; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(); diff --git a/src/backend/PartKeepr/Auth/AuthService.php b/src/backend/PartKeepr/Auth/AuthService.php @@ -0,0 +1,52 @@ +<?php +namespace PartKeepr\Auth; + +use PartKeepr\Service\AnonService, + PartKeepr\User\User, + PartKeepr\User\UserManager, + PartKeepr\User\Exceptions\InvalidLoginDataException, + PartKeepr\Session\SessionManager; + +class AuthService extends AnonService { + /** + * Logs in the given user. If the login was successful, + * a session is automatically started. + * + * @throws InvalidLoginDataException + */ + public function login () { + $this->requireParameter("username"); + $this->requireParameter("password"); + + /* Build a temporary user */ + $user = new User; + $user->setRawUsername($this->getParameter("username")); + $user->setHashedPassword($this->getParameter("password")); + + $authenticatedUser = UserManager::getInstance()->authenticate($user); + + if ($authenticatedUser !== false) { + /* Start Session */ + $session = SessionManager::getInstance()->startSession($authenticatedUser); + + $aPreferences = array(); + + foreach ($session->getUser()->getPreferences() as $result) { + $aPreferences[] = $result->serialize(); + } + + return array( + "sessionid" => $session->getSessionID(), + "username" => $this->getParameter("username"), + "admin" => $session->getUser()->isAdmin(), + "userPreferences" => array( + "response" => array( + "data" => $aPreferences + ))); + } else { + throw new InvalidLoginDataException(); + } + + + } +} diff --git a/src/backend/PartKeepr/Category/AbstractCategory.php b/src/backend/PartKeepr/Category/AbstractCategory.php @@ -0,0 +1,202 @@ +<?php +namespace PartKeepr\Category; + +use PartKeepr\Util\BaseEntity; +use PartKeepr\Util\Serializable; +use DoctrineExtensions\NestedSet\Node; + +/** + * @MappedSuperclass + * @Table(indexes={@index(columns={"lft"}),@index(columns={"rgt"})}) + * + * Represents an abstract category. This class isn't directly usable; you need to inherit it to take advantage of + * the AbstractCategoryManager. + * + * If you are interested on how NestedSets work, please read http://en.wikipedia.org/wiki/Nested_set_model + */ +class AbstractCategory extends BaseEntity implements Node, Serializable { + /** + * The "left" property of the nested set + * @Column(type="integer") + * @var integer + */ + private $lft; + + /** + * The "right" property of the nested set + * @Column(type="integer") + * @var integer + */ + private $rgt; + + /** + * The name of the category + * @Column(length=128) + * @var string + */ + private $name; + + /** + * The description of the category + * @Column(type="text",nullable=true) + * @var string + */ + private $description; + + /** + * Holds the parent node ID. Note that this + * is not a persistant value, but rather calculated + * or set on the fly. + * @var int + */ + private $parent; + + /** + * Holds the category path. + * + * @Column(type="text",nullable=true) + * + * @var string + */ + private $categoryPath; + + /** + * Sets the name of this category + * @param string $name The name to set + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name of this category + * @return string The category name + */ + public function getName () { + return $this->name; + } + + /** + * Sets the parent for this category. + * + * @param int $id The parent node + */ + public function setParent ($id) { + $this->parent = $id; + } + + /** + * Returns the parent node for this node. + * @return int The parent node + */ + public function getParent () { + return $this->parent; + } + + /** + * Sets the description for this category + * @param string $description The description of this category + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description of this category + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * Returns the "left" value of the nested set. + * + * @return int The left value + * + * (non-PHPdoc) + * @see DoctrineExtensions\NestedSet.Node::getLeftValue() + */ + public function getLeftValue() { + return $this->lft; + } + + /** + * Sets the "left" value. + * + * @param $lft integer The left value + * (non-PHPdoc) + * @see DoctrineExtensions\NestedSet.Node::setLeftValue() + */ + public function setLeftValue($lft) { + $this->lft = $lft; + } + + /** + * Returns the "right" value of the nested set. + * + * @return int The right value + * + * (non-PHPdoc) + * @see DoctrineExtensions\NestedSet.Node::getRightValue() + */ + public function getRightValue() { + return $this->rgt; + } + + /** + * Sets the "right" value of the nested set + * + * @param $rgt int The right value + * + * (non-PHPdoc) + * @see DoctrineExtensions\NestedSet.Node::setRightValue() + */ + public function setRightValue($rgt) { + $this->rgt = $rgt; + } + + /** + * Serializes the entity. + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "description" => $this->getDescription() + ); + } + + /** + * Returns a string representation of the current node. + * + * @return string The node name + * + * (non-PHPdoc) + * @see DoctrineExtensions\NestedSet.Node::__toString() + */ + public function __toString () { + return $this->getName(); + } + + /** + * Retrieves the category path + * + * @return string The category path + */ + public function getCategoryPath () { + return $this->categoryPath; + } + + /** + * Sets the category path. + * + * THIS IS ONLY TO BE CALLED FROM THE CATEGORYMANAGER! DON'T MESS WITH IT! + * + * @param string $categoryPath + */ + public function setCategoryPath ($categoryPath) { + $this->categoryPath = $categoryPath; + } + +} diff --git a/src/backend/PartKeepr/Category/AbstractCategoryManager.php b/src/backend/PartKeepr/Category/AbstractCategoryManager.php @@ -0,0 +1,222 @@ +<?php +namespace PartKeepr\Category; + +use PartKeepr\Util\Singleton, + PartKeepr\Category\Category, + PartKeepr\Util\SerializableException, + PartKeepr\Category\Exceptions\CategoryNotFoundException, + PartKeepr\PartKeepr, + PartKeepr\Util\Configuration, + DoctrineExtensions\NestedSet\Manager, + DoctrineExtensions\NestedSet\Config, + DoctrineExtensions\NestedSet\NodeWrapper; + +abstract class AbstractCategoryManager extends Singleton { + /** + * Holds the node manager + * @var object The node manager + */ + private $nodeManager; + + /** + * Holds the FQCN of the target entity + * @var PartKeepr\Category\AbstractCategory + */ + protected $categoryClass = "PartKeepr\Category\AbstractCategory"; + + /** + * Returns the node manager. Creates it if it doesn't exist. + * @todo Can this method be made private? + * @return Manager The node manager + */ + public function getNodeManager () { + if (!$this->nodeManager) { + $config = new Config(PartKeepr::getEM(), $this->categoryClass); + + $this->nodeManager = new Manager($config); + } + + return $this->nodeManager; + } + + /** + * Returns the child node id's for a given node id. + * @param integer $id The ID for which to retrieve the child nodes + * @return array An array of the children id's + * @todo Refactor this method name to indicate that it operates on IDs only. + */ + public function getChildNodes ($id) { + $category = $this->getCategory($id); + + $aData = array(); + + foreach ($category->getDescendants() as $cat) { + $aData[] = $cat->getNode()->getId(); + } + return $aData; + } + + /** + * Returns all categories. + * @return The category tree + */ + public function getAllCategories () { + return $this->getNodeManager()->fetchTree(1); + } + + /** + * Ensures that the root node exists. If not, this method creates it. + */ + public function ensureRootExists () { + /* Check if the root node exists */ + $rootNode = $this->getNodeManager()->fetchTree(1); + + if ($rootNode === null) { + $this->createRootNode(); + } + } + + /** + * Returns the root node for the category tree. + * @return The category root node + */ + public function getRootNode () { + return $this->getNodeManager()->fetchTree(1); + } + + /** + * Create the root node for the category tree. + */ + public function createRootNode () { + $rootNode = new $this->categoryClass(); + $rootNode->setName("Root Category"); + $rootNode->setDescription(""); + + $this->getNodeManager()->createRoot($rootNode); + } + + /** + * Adds a given category. + * @param Category $category The category to add to the tree + * @return Category the added category + */ + public function addCategory (AbstractCategory $category) { + $parent = $category->getParent(); + + if ($parent == 0) { + $parent = $this->getRootNode(); + } else { + $parent = PartKeepr::getEM()->find($this->categoryClass, $parent); + $parent = new NodeWrapper($parent, $this->getNodeManager()); + } + + $node = $parent->addChild($category); + + // Force category path update + $this->updateCategoryPaths($node); + + // Flush the category path changes + PartKeepr::getEM()->flush(); + + return $node; + } + + /** + * Deletes the given category ID. + * @param $id int The category id to delete + * @throws CategoryNotFoundException If the category wasn't found + */ + public function deleteCategory ($id) { + $this->getCategory($id)->delete(); + } + + /** + * Returns the category with the given ID. + * @param int $id The category id + * @throws CategoryNotFoundException If the category wasn't found + */ + public function getCategory ($id) { + $category = $this->loadCategoryById($id); + + return new NodeWrapper($category, $this->getNodeManager()); + } + + /** + * Returns the overall category count currently existing. + * @return int The amount of categories in the database + */ + public function getCategoryCount () { + $dql = "SELECT COUNT(c.id) FROM ".$this->categoryClass." c"; + + return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); + } + + /** + * Updates the category paths for a given node and all children. + * + * This method is usually called whenever a category is moved. + * + * @param NodeWrapper $startNode The node to start updating at + */ + public function updateCategoryPaths (NodeWrapper $startNode) { + $pathSeparator = Configuration::getOption("partkeepr.category.path_separator", " ➤ "); + + $startNode->getNode()->setCategoryPath($startNode->getPath($pathSeparator, true)); + + foreach ($startNode->getChildren() as $child) { + $this->updateCategoryPaths($child); + } + } + + /** + * Creates a category tree by an array of category names + * @param array $aCategoryNames + * @param Category A category where to start searching at + */ + public function createCategoryTreeByArray ($aCategoryNames, NodeWrapper $rootNode = null) { + if (count($aCategoryNames) == 0) { + return false; + } + + $categoryName = array_shift($aCategoryNames); + + if ($rootNode === null) { + $rootNode = $this->getRootNode(); + } + + $bFound = false; + foreach ($rootNode->getChildren() as $child) { + if ($child->getNode()->getName() == $categoryName) { + $bFound = true; + $category = $child->getNode(); + break; + } + } + + if ($bFound === false) { + $category = new $this->categoryClass(); + $category->setName($categoryName); + $category->setDescription(""); + $category->setParent($rootNode->getId()); + $this->addCategory($category); + } + + $result = $this->createCategoryTreeByArray($aCategoryNames,new NodeWrapper($category, $this->getNodeManager())); + + if ($result === false) { + return $category; + } else { + return $result; + } + } + + /** + * Loads a category by id + * @param string $id + */ + protected function loadCategoryById($id) { + $class = $this->categoryClass; + + return $class::loadById($id); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Category/AbstractCategoryService.php b/src/backend/PartKeepr/Category/AbstractCategoryService.php @@ -0,0 +1,145 @@ +<?php +namespace PartKeepr\Category; + +use PartKeepr\PartKeepr, + PartKeepr\Service\Service, + PartKeepr\Category\CategoryManager, + DoctrineExtensions\NestedSet\NodeWrapper; + + +abstract class AbstractCategoryService extends Service { + protected $categoryManagerClass = "PartKeepr\Category\AbstractCategoryManager"; + protected $categoryClass = "PartKeepr\Category\AbstractCategory"; + + /** + * Returns all categories found in the system. + * @return array A serialized tree + */ + public function getCategories () { + $categories = $this->getCategoryManager()->getAllCategories( + $this->getParameter("parent", 0)); + + return $this->serializeTree($categories); + } + + /** + * Moves the given category from one to another category. + */ + public function moveCategory () { + $this->requireParameter("category"); + $this->requireParameter("target"); + + $category = $this->getCategoryManager()->getCategory($this->getParameter("category")); + + if (intval($this->getParameter("target", 0)) !== 0) { + + $parent = $this->getCategoryManager()->getCategory($this->getParameter("target")); + + $category->moveAsLastChildOf($parent); + $this->getCategoryManager()->updateCategoryPaths($category); + + } + } + + /** + * Deletes the given category. + */ + public function deleteCategory () { + $this->requireParameter("id"); + + $this->getCategoryManager()->deleteCategory($this->getParameter("id")); + + return array("id" => $this->getParameter("id")); + } + + /** + * Updates the given category. + */ + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + + $category = $this->getCategoryManager()->getCategory($this->getParameter("id")); + + $category->getNode()->setName($this->getParameter("name")); + $category->getNode()->setDescription($this->getParameter("description", "")); + + PartKeepr::getEM()->persist($category->getNode()); + + $this->getCategoryManager()->updateCategoryPaths($category); + + return array("data" => $this->serializeCategory($category)); + } + + public function create () { + $this->requireParameter("name"); + $this->requireParameter("parent"); + + $category = new $this->categoryClass; + $category->setName($this->getParameter("name")); + $category->setDescription($this->getParameter("description", "")); + $category->setParent($this->getParameter("parent")); + + $category = $this->getCategoryManager()->addCategory($category); + + $this->getCategoryManager()->updateCategoryPaths($category); + + return array("data" => $this->serializeCategory($category)); + } + + public function destroy () { + return $this->deleteCategory(); + } + + private function serializeCategory ($category) { + $data = $category->getNode()->serialize(); + + if ($category->getParent() !== null) { + $data["parent"] = $category->getParent()->getNode()->getId(); + $data["parentName"] = $category->getParent()->getNode()->getName(); + } + + return $data; + } + + /** + * Returns all categories + */ + public function getAllCategories () { + return $this->serializeTree($this->getCategoryManager()->getAllCategories()); + } + + /** + * Serializes the given NodeWrapper as array including all children. + * @param NodeWrapper $node The category nodewrapper to serialize + * @throws \Exception + */ + public function serializeTree (NodeWrapper $node = null) { + if ($node == null) { + throw new \Exception("Node must not be null!"); + } + + $aData = $node->getNode()->serialize(); + + $aData["children"] = array(); + + if (count($node->getChildren()) == 0) { + $aData["leaf"] = true; + } else { + $aData["expanded"] = true; + } + + foreach ($node->getChildren() as $child) { + $aData["children"][] = $this->serializeTree($child); + + } + + return $aData; + } + + public function getCategoryManager () { + $categoryManager = $this->categoryManagerClass; + + return $categoryManager::getInstance(); + } +} diff --git a/src/backend/PartKeepr/Category/Exceptions/CategoryNotFoundException.php b/src/backend/PartKeepr/Category/Exceptions/CategoryNotFoundException.php @@ -0,0 +1,15 @@ +<?php +namespace PartKeepr\Category\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** + * Thrown when the requested category was not found. + */ +class CategoryNotFoundException extends SerializableException { + public function __construct ($id) { + parent::__construct(sprintf(PartKeepr::i18n("Category %d not found."), $id)); + } +} +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/CronLogger/CronLogger.php b/src/backend/PartKeepr/CronLogger/CronLogger.php @@ -0,0 +1,58 @@ +<?php +namespace PartKeepr\CronLogger; + +use PartKeepr\UploadedFile\UploadedFile, + PartKeepr\Util\BaseEntity, + PartKeepr\Util\Serializable, + PartKeepr\Util\Deserializable; + +/** + * Holds a project attachment + * @Entity + **/ +class CronLogger extends BaseEntity { + /** + * @Column(type="datetime") + * @var \DateTime + */ + private $lastRunDate; + + /** + * @Column(type="string") + * @var string + */ + private $cronjob; + + /** + * Sets the last run date and time for this entry + * @param \DateTime $date The date and time + */ + public function setLastRunDate (\DateTime $date) { + $this->lastRunDate = $date; + } + + /** + * Returns the date and time for this entry + * + * @return \DateTime the date and time for this entry + */ + public function getLastRunDate () { + return $this->lastRunDate; + } + + /** + * Sets the cronjob for this entry + * @param string $cronjob the title for this entry + */ + public function setCronjob ($cronjob) { + $this->cronjob = $cronjob; + } + + /** + * Returns the cronjob for this entry + * @return string the title + */ + public function getCronjob () { + return $this->cronjob; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/CronLogger/CronLoggerManager.php b/src/backend/PartKeepr/CronLogger/CronLoggerManager.php @@ -0,0 +1,86 @@ +<?php +namespace PartKeepr\CronLogger; + +use PartKeepr\Manager\AbstractManager, + PartKeepr\PartKeepr; + +class CronLoggerManager 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\CronLogger\CronLogger'; + } + + /** + * 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"; + } + + /** + * Marks a specific cronjob as ran + * @param string $cronjob The name of the cronjob + */ + public function markCronRun ($cronjob) { + $dql = "SELECT c FROM PartKeepr\CronLogger\CronLogger c WHERE c.cronjob = :cronjob"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("cronjob", $cronjob); + + try { + $result = $query->getSingleResult(); + } catch (\Exception $e) { + $result = new CronLogger(); + $result->setCronjob($cronjob); + PartKeepr::getEM()->persist($result); + } + + $result->setLastRunDate(new \DateTime()); + + PartKeepr::getEM()->flush(); + } + + /** + * Returns a list of all inactive cronjobs + * + * @param none + * @return array A string of cronjob names which aren't running + */ + public function getInactiveCronjobs () { + $dql = "SELECT c.cronjob FROM PartKeepr\CronLogger\CronLogger c WHERE c.cronjob = :cronjob"; + $dql .= " AND c.lastRunDate > :date"; + + $query = PartKeepr::getEM()->createQuery($dql); + + $date = new \DateTime(); + $date->sub(new \DateInterval('P1D')); + $query->setParameter("date", $date); + + $failedCronjobs = array(); + + foreach (PartKeepr::getRequiredCronjobs() as $cronjob) { + $query->setParameter("cronjob", $cronjob); + + try { + $query->getSingleResult(); + } catch (\Exception $e) { + $failedCronjobs[] = $cronjob; + } + + } + + return $failedCronjobs; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Distributor/Distributor.php b/src/backend/PartKeepr/Distributor/Distributor.php @@ -0,0 +1,231 @@ +<?php +namespace PartKeepr\Distributor; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr; + +/** + * Represents a distributor + * @Entity **/ +class Distributor extends BaseEntity implements Serializable, Deserializable { + /** + * Holds the name of the distributor + * @Column(type="string",unique=true) + * @var string + */ + private $name; + + /** + * Holds the address of the distributor + * @Column(type="text",nullable=true) + * @var string + */ + private $address; + + /** + * Holds the URL of the distributor + * @Column(type="string",nullable=true) + * @var string + */ + private $url; + + /** + * Holds the phone number of the distributor + * @Column(type="string",nullable=true) + * @var string + */ + private $phone; + + /** + * Holds the fax number of the distributor + * @Column(type="string",nullable=true) + * @var string + */ + private $fax; + + /** + * Holds the email of the distributor + * @Column(type="string",nullable=true) + * @var string + */ + private $email; + + /** + * Holds a comment for the distributor + * @Column(type="text",nullable=true) + * @var string + */ + private $comment; + + /** + * Sets the name for the distributor + * + * @param string $name The distributor's name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name of the distributor + * @return string The distributor's name + */ + public function getName () { + return $this->name; + } + + /** + * Sets the address of this distributor + * + * @param string $address The address of the distributor + */ + public function setAddress ($address) { + $this->address = $address; + } + + /** + * Returns the address of this distributor + * @return string The address of this distributor + */ + public function getAddress () { + return $this->address; + } + + /** + * Sets the phone number for this distributor + * + * @param string $phone The phone number of this distributor + */ + public function setPhone ($phone) { + $this->phone = $phone; + } + + /** + * Returns the phone number of this distributor + * @return string The phone number + */ + public function getPhone () { + return $this->phone; + } + + /** + * Sets the fax number for this distributor + * + * @param string $fax The fax number + */ + public function setFax ($fax) { + $this->fax = $fax; + } + + /** + * Returns the fax number for this distributor + * + * @return string $fax The fax number + */ + public function getFax () { + return $this->fax; + } + + /** + * Sets the comment for this distributor + * + * @param string $comment The comment for this distributor + */ + public function setComment ($comment) { + $this->comment = $comment; + } + + /** + * Returns the comment for this distributor + * + * @return string The comment + */ + public function getComment () { + return $this->comment; + } + + /** + * Sets the email for this distributor + * + * @param string $email The email for this distributor + */ + public function setEmail ($email) { + $this->email = $email; + } + + /** + * Returns the email for this distributor + * @return string The email + */ + public function getEmail () { + return $this->email; + } + + /** + * Sets the URL for this distributor + * + * @param string $url The URL for this distributor + */ + public function setURL ($url) { + $this->url = $url; + } + + /** + * Returns the URL for this distributor + * @return string The URL + */ + public function getURL () { + return $this->url; + } + + /** + * Returns the distributor in serialized form. + * @return array The serialized distributor + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "url" => $this->getURL(), + "address" => $this->getAddress(), + "email" => $this->getEmail(), + "comment" => $this->getComment(), + "phone" => $this->getPhone(), + "fax" => $this->getFax() + ); + } + + /** + * Deserializes the distributor + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "url": + $this->setURL($value); + break; + case "comment": + $this->setComment($value); + break; + case "fax": + $this->setFax($value); + break; + case "phone": + $this->setPhone($value); + break; + case "email": + $this->setEmail($value); + break; + case "address": + $this->setAddress($value); + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Distributor/DistributorManager.php b/src/backend/PartKeepr/Distributor/DistributorManager.php @@ -0,0 +1,107 @@ +<?php +namespace PartKeepr\Distributor; + +use PartKeepr\Util\Singleton, + PartKeepr\Distributor\Distributor, + PartKeepr\PartKeepr, + PartKeepr\Category\CategoryManager, + PartKeepr\Distributor\Exceptions\DistributorNotFoundException; + +class DistributorManager extends Singleton { + /** + * Returns a list of distributors. + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter A string to filter the distributor's name by, default empty + */ + public function getDistributors ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st.id, st.name, st.url, st.email, st.comment, st.address")->from("PartKeepr\Distributor\Distributor","st"); + + if ($filter != "") { + $qb = $qb->where("LOWER(st.name) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\Distributor\Distributor","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Returns a distributor by ID. + * + * @param int $id The distributor id + * @return Distributor The distributor + * @throws EntityNotFoundException If no distributor with the ID was found + */ + public function getDistributor ($id) { + return Distributor::loadById($id); + } + + /** + * Creates a new distributor with the given name. + * @param string $name The name of the distributor + * @return Distributor The new distributor object + */ + public function addDistributor ($name) { + $distributor = new Distributor(); + $distributor->setName($name); + + PartKeepr::getEM()->persist($distributor); + PartKeepr::getEM()->flush(); + + return $distributor; + } + + /** + * Deletes a distributor by id + * + * @param int $id The ID of the distributor to delete + */ + public function deleteDistributor ($id) { + $distributor = $this->getDistributor($id); + + PartKeepr::getEM()->remove($distributor); + PartKeepr::getEM()->flush(); + } + + /** + * Retrieves a distributor by its name. + * + * @param string $name The name of the distributor to retrieve + * @throws Doctrine\ORM\NoResultException If the distributor was not found + */ + public function getDistributorByName ($name) { + $dql = "SELECT d FROM PartKeepr\Distributor\Distributor d WHERE d.name = :name"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $name); + + return $query->getSingleResult(); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Distributor/DistributorService.php b/src/backend/PartKeepr/Distributor/DistributorService.php @@ -0,0 +1,82 @@ +<?php +namespace PartKeepr\Distributor; +use PartKeepr\Service\RestfulService; + +use PartKeepr\Service\Service, + PartKeepr\Part\PartManager, + PartKeepr\Stock\StockEntry, + PartKeepr\PartKeepr, + PartKeepr\Session\SessionManager; + +class DistributorService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return array("data" => DistributorManager::getInstance()->getDistributor($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "name", + "direction" => "ASC"); + } + return DistributorManager::getInstance()->getDistributors( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $this->requireParameter("name"); + + $distributor = new Distributor; + $distributor->deserialize($this->getParameters()); + + PartKeepr::getEM()->persist($distributor); + PartKeepr::getEM()->flush(); + + return array("data" => $distributor->serialize()); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + + $distributor = Distributor::loadById($this->getParameter("id")); + $distributor->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $distributor->serialize()); + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + $this->requireParameter("id"); + + DistributorManager::getInstance()->deleteDistributor($this->getParameter("id")); + + return array("data" => null); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Footprint/Footprint.php b/src/backend/PartKeepr/Footprint/Footprint.php @@ -0,0 +1,192 @@ +<?php +namespace PartKeepr\Footprint; +use PartKeepr\Util\Deserializable; + +use PartKeepr\Util\Serializable; +use PartKeepr\FootprintCategory\FootprintCategory; +use PartKeepr\Util\BaseEntity; + +/** @Entity */ + +class Footprint extends BaseEntity implements Serializable, Deserializable { + /** + * Holds the footprint name + * @Column(length=64,unique=true) + * @var string + */ + private $name; + + /** + * Holds the footprint description + * @Column(type="text",nullable=true) + * @var string + */ + private $description; + + /** + * The category of the footprint + * @ManyToOne(targetEntity="PartKeepr\FootprintCategory\FootprintCategory") + * @var Category + */ + private $category; + + /** + * Holds the footprint image + * @OneToOne(targetEntity="PartKeepr\Footprint\FootprintImage",mappedBy="footprint",cascade={"persist", "remove"}) + * @var FootprintImage + */ + private $image; + + /** + * Holds the footprint attachments + * @OneToMany(targetEntity="PartKeepr\Footprint\FootprintAttachment",mappedBy="footprint",cascade={"persist", "remove"}) + * @var FootprintAttachment + */ + private $attachments; + + /** + * Constructs a new Footprint entity + */ + public function __construct () { + $this->attachments = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Sets the name of this footprint + * + * @param string $name The footprint name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name of this footprint + * @return string The name of this footprint + */ + public function getName () { + return $this->name; + } + + /** + * Sets the description of this footprint + * @param string $description The description + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description of this footprint + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * Sets the category for this footprint + * @param \PartKeepr\FootprintCategory\FootprintCategory $category The category + */ + public function setCategory (FootprintCategory $category) { + $this->category = $category; + } + + /** + * Returns the category of this footprint + * @return FootprintCategory The footprint category + */ + public function getCategory () { + return $this->category; + } + + /** + * Sets the footprint image + * @param FootprintImage $image The footprint image + */ + public function setImage (FootprintImage $image) { + $this->image = $image; + $image->setFootprint($this); + } + + /** + * Returns the footprint image + * @return FootprintImage The footprint image + */ + public function getImage () { + return $this->image; + } + + /** + * Returns the attachments for this footprint + * @return ArrayCollection The attachments + */ + public function getAttachments () { + return $this->attachments; + } + + /** + * Serializes the footprint + * @return array the serialized footprint + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "description" => $this->getDescription(), + "image_id" => is_object($this->getImage()) ? $this->getImage()->getId() : null, + "category" => is_object($this->getCategory()) ? $this->getCategory()->getId() : null, + "attachments" => $this->serializeChildren($this->getAttachments()) + ); + } + + /** + * Deserializes the footprint + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "description": + $this->setDescription($value); + break; + case "image_id": + if ($value == "") { + echo "/** Breaking because of empty value */"; + break; } + + try { + $image = FootprintImage::loadById($value); + $this->setImage($image); + } catch (\Exception $e) { + if ($this->getImage()) { + // Image was not found, maybe a temporary image? + $this->getImage()->replaceFromTemporaryFile($value); + } else { + $image = FootprintImage::createFromTemporaryFile($value); + $this->setImage($image); + } + } + + break; + case "category": + try { + $category = FootprintCategory::loadById($value); + $this->setCategory($category); + } catch (\Exception $e) { + // Category was not found, do not change category. + } + break; + case "attachments": + $this->deserializeChildren($value, $this->getAttachments(), "PartKeepr\Footprint\FootprintAttachment"); + foreach ($this->getAttachments() as $attachment) { + $attachment->setFootprint($this); + } + break; + } + } + } +} diff --git a/src/backend/PartKeepr/Footprint/FootprintAttachment.php b/src/backend/PartKeepr/Footprint/FootprintAttachment.php @@ -0,0 +1,101 @@ +<?php +namespace PartKeepr\Footprint; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\UploadedFile\UploadedFile; + +/** + * Holds a footprint attachment + * @Entity + **/ +class FootprintAttachment extends UploadedFile implements Serializable, Deserializable { + /** + * The description of this attachment + * @Column(type="text") + * @var string + */ + private $description; + + /** + * Creates a new footprint attachment + */ + public function __construct () { + parent::__construct(); + $this->setType("FootprintAttachment"); + } + /** + * The footprint object + * @ManyToOne(targetEntity="PartKeepr\Footprint\Footprint") + * @var Footprint + */ + private $footprint = null; + + /** + * Sets the footprint + * @param Footprint $footprint The footprint to set + */ + public function setFootprint (Footprint $footprint) { + $this->footprint = $footprint; + } + + /** + * Returns the footprint + * @return Footprint the footprint + */ + public function getFootprint () { + return $this->footprint; + } + + /** + * Sets the description for this attachment + * @param string $description The attachment description + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description for this attachment + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * + * Serializes this footprint attachment + * @return array The serialized footprint attachment + */ + public function serialize () { + return array( + "id" => $this->getId(), + "footprint_id" => $this->getFootprint()->getId(), + "originalFilename" => $this->getOriginalFilename(), + "mimetype" => $this->getMimetype(), + "extension" => $this->getExtension(), + "size" => $this->getSize(), + "description" => $this->getDescription()); + } + + /** + * Deserializes the footprint attachment + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + if (array_key_exists("id", $parameters)) { + if (substr($parameters["id"], 0, 4) === "TMP:") { + $this->replaceFromTemporaryFile($parameters["id"]); + } + } + + foreach ($parameters as $key => $value) { + switch ($key) { + case "description": + $this->setDescription($value); + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Footprint/FootprintImage.php b/src/backend/PartKeepr/Footprint/FootprintImage.php @@ -0,0 +1,50 @@ +<?php +namespace PartKeepr\Footprint; + +use PartKeepr\Util\Serializable, + PartKeepr\Image\Image; + +/** + * Holds a footprint image + * @Entity + **/ +class FootprintImage extends Image implements Serializable { + /** + * The footprint object + * @OneToOne(targetEntity="PartKeepr\Footprint\Footprint",inversedBy="image") + * @var Footprint + */ + private $footprint = null; + + /** + * Creates a new IC logo instance + */ + public function __construct () { + parent::__construct(Image::IMAGE_FOOTPRINT); + } + + /** + * Sets the footprint + * @param Footprint $footprint The footprint to set + */ + public function setFootprint (Footprint $footprint) { + $this->footprint = $footprint; + } + + /** + * Returns the footprint + * @return Footprint the footprint + */ + public function getFootprint () { + return $this->footprint; + } + + /** + * + * Serializes this ic logo + * @return array The serialized ic logo + */ + public function serialize () { + return array("id" => $this->getId(), "footprint_id" => $this->getFootprint()->getId()); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Footprint/FootprintManager.php b/src/backend/PartKeepr/Footprint/FootprintManager.php @@ -0,0 +1,158 @@ +<?php +namespace PartKeepr\Footprint; + +use PartKeepr\Util\Singleton, + PartKeepr\Util\SerializableException, + PartKeepr\Footprint\Footprint, + PartKeepr\PartKeepr, + PartKeepr\Util\Exceptions\EntityNotFoundException; + +class FootprintManager extends Singleton { + /** + * Returns a list of footprints. + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter A string to filter the footprint's name by, default empty + */ + public function getFootprints ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("f.id, f.name, f.description, im.id AS image_id, ca.id AS category")->from("PartKeepr\Footprint\Footprint","f") + ->leftJoin("f.image", "im") + ->leftJoin("f.category", "ca"); + + if ($filter != "") { + $qb = $qb->where("LOWER(f.name) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("f.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(f.id)")->from("PartKeepr\Footprint\Footprint","f")->leftJoin("f.image", "im"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(f.name) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Creates a new footprint + * + * @param string $footprint The footprint's name + * @throws \PartKeepr\Util\SerializableException + * @throws PDOException + */ + public function addFootprint ($name) { + $fp = new Footprint(); + $fp->setName($name); + + // @todo Port the UniqueEntityValidator from Symfony2 to here. + try { + PartKeepr::getEM()->persist($fp); + PartKeepr::getEM()->flush(); + } catch (\PDOException $e) { + if ($e->getCode() == "23000") { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Footprint %s already exists!"), $name)); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to add the footprint %s, but a footprint with the same name already exists."), $name)); + + throw $exception; + } else { + throw $e; + } + } + + return $fp; + } + + /** + * Deletes the footprint with the given id. + * + * @param int $id The footprint id to delete + * @throws \PartKeepr\Util\SerializableException + */ + public function deleteFootprint ($id) { + $footprint = Footprint::loadById($id); + + try { + PartKeepr::getEM()->remove($footprint); + PartKeepr::getEM()->flush(); + } catch (\PDOException $e) { + if ($e->getCode() == "23000") { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Footprint %s is in use by some parts!"), $footprint->getName())); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the footprint %s, but there are parts which use this footprint."), $footprint->getName())); + + throw $exception; + } + } + } + + /** + * Loads a footprint by id + * @param int $id The footprint id + */ + public function getFootprint ($id) { + return Footprint::loadById($id); + } + + /** + * Finds or creates a footprint by name. + * + * @param mixed $footprint Either the ID or the footprint's name to find + */ + public function getOrCreateFootprint ($footprint) { + try { + $footprint = Footprint::loadById($footprint); + return $footprint; + } catch (EntityNotFoundException $e) {} + + $dql = "SELECT f FROM PartKeepr\Footprint\Footprint f WHERE f.name = :name"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $footprint); + + try { + $footprint = $query->getSingleResult(); + return $footprint; + } catch (\Exception $e) {} + + $fp = new Footprint(); + $fp->setName($footprint); + + PartKeepr::getEM()->persist($fp); + + return $fp; + } + + /** + * Retrieves a distributor by its name. + * + * @param string $name The name of the distributor to retrieve + * @throws Doctrine\ORM\NoResultException If the distributor was not found + */ + public function getFootprintByName ($name) { + $dql = "SELECT fp FROM PartKeepr\Footprint\Footprint fp WHERE fp.name = :name"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $name); + + return $query->getSingleResult(); + } +} diff --git a/src/backend/PartKeepr/Footprint/FootprintService.php b/src/backend/PartKeepr/Footprint/FootprintService.php @@ -0,0 +1,96 @@ +<?php +namespace PartKeepr\Footprint; + +use PartKeepr\TempImage\TempImage, + PartKeepr\FootprintCategory\FootprintCategory, + PartKeepr\Service\Service, + PartKeepr\Service\RestfulService, + PartKeepr\PartKeepr, + PartKeepr\Footprint\FootprintManager; + +class FootprintService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return array("data" => FootprintManager::getInstance()->getFootprint($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "name", + "direction" => "ASC"); + } + return FootprintManager::getInstance()->getFootprints( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $this->requireParameter("name"); + + $footprint = new Footprint(); + $footprint->deserialize($this->getParameters()); + + PartKeepr::getEM()->persist($footprint); + + PartKeepr::getEM()->flush(); + + return array("data" => $footprint->serialize()); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + $footprint = Footprint::loadById($this->getParameter("id")); + + $footprint->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $footprint->serialize()); + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + $this->requireParameter("id"); + + FootprintManager::getInstance()->deleteFootprint($this->getParameter("id")); + + return array("data" => null); + } + + public function moveFootprint () { + $this->requireParameter("targetCategory"); + $this->requireParameter("id"); + + $footprint = Footprint::loadById($this->getParameter("id")); + $category = FootprintCategory::loadById($this->getParameter("targetCategory")); + + $footprint->setCategory($category); + + PartKeepr::getEM()->flush(); + } + +} diff --git a/src/backend/PartKeepr/FootprintAttachment/FootprintAttachmentManager.php b/src/backend/PartKeepr/FootprintAttachment/FootprintAttachmentManager.php @@ -0,0 +1,68 @@ +<?php +namespace PartKeepr\FootprintAttachment; + +use PartKeepr\Util\Singleton, + PartKeepr\Footprint\Footprint, + PartKeepr\PartKeepr; + +class FootprintAttachmentManager extends Singleton { + /** + * Returns a list of footprint attachments + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter The footprint id + */ + public function getFootprintAttachments ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st")->from("PartKeepr\Footprint\FootprintAttachment","st") + ->leftJoin('st.footprint', "fp"); + + if ($filter != "") { + $footprint = Footprint::loadById($filter); + $qb = $qb->where("st.footprint = :footprint"); + $qb->setParameter("footprint", $footprint); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\Footprint\FootprintAttachment","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("st.footprint = :footprint"); + $totalQueryBuilder->setParameter("footprint", $footprint); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + $aData = array(); + foreach ($result as $item) { + $aData[] = $item->serialize(); + } + return array("data" => $aData, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Returns a footprint attachment by id + * @param int $id The footprint attachment id + */ + public function getFootprintAttachment ($id) { + return FootprintAttachment::loadById($id); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/FootprintAttachment/FootprintAttachmentService.php b/src/backend/PartKeepr/FootprintAttachment/FootprintAttachmentService.php @@ -0,0 +1,102 @@ +<?php +namespace PartKeepr\FootprintAttachment; + +use PartKeepr\Footprint\FootprintAttachment, + PartKeepr\UploadedFile\TempUploadedFile, + PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Footprint\Footprint, + PartKeepr\Session\SessionManager; + +class FootprintAttachmentService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return FootprintAttachmentManager::getInstance()->getFootprintAttachment($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"] == "footprint_id") { + if (array_key_exists("value", $item)) { + $filter = $item["value"]; + } + } + } + } + } + return FootprintAttachmentManager::getInstance()->getFootprintAttachments( + $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); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $this->requireParameter("tmp_id"); + $this->requireParameter("footprint_id"); + + $tmpImage = TempUploadedFile::loadById($this->getParameter("tmp_id")); + + $file = new FootprintAttachment(); + + $footprint = Footprint::loadById($this->getParameter("footprint_id")); + + $file->setFootprint($footprint); + $file->replace($tmpImage->getFilename()); + $file->setOriginalFilename($tmpImage->getOriginalFilename()); + $file->setDescription($this->getParameter("description")); + PartKeepr::getEM()->persist($file); + PartKeepr::getEM()->flush(); + + return $file->serialize(); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + $this->requireParameter("id"); + + $file = FootprintAttachment::loadById($this->getParameter("id")); + + PartKeepr::getEM()->remove($file); + PartKeepr::getEM()->flush(); + + return array("data" => null); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/FootprintCategory/FootprintCategory.php b/src/backend/PartKeepr/FootprintCategory/FootprintCategory.php @@ -0,0 +1,14 @@ +<?php +namespace PartKeepr\FootprintCategory; + +use PartKeepr\Category\AbstractCategory; + +/** + * @Entity + * @Table(indexes={@index(columns={"lft"}),@index(columns={"rgt"})}) + * The entity for our footprint categories + * + */ +class FootprintCategory extends AbstractCategory { + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/FootprintCategory/FootprintCategoryManager.php b/src/backend/PartKeepr/FootprintCategory/FootprintCategoryManager.php @@ -0,0 +1,42 @@ +<?php +namespace PartKeepr\FootprintCategory; + +use PartKeepr\Category\AbstractCategoryManager; +use DoctrineExtensions\NestedSet\NodeWrapper; +use PartKeepr\Util\SerializableException; +use PartKeepr\PartKeepr; + +class FootprintCategoryManager extends AbstractCategoryManager { + protected $categoryClass = "PartKeepr\FootprintCategory\FootprintCategory"; + + /** + * Deletes the given category ID. + * @param $id int The category id to delete + * @throws CategoryNotFoundException If the category wasn't found + */ + public function deleteCategory ($id) { + $category = $this->getCategory($id); + + try { + + if ($category->hasChildren()) { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains other categories."), $category->getNode()->getName())); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains other categories. Please move the categories or delete them first."), $category->getNode()->getName())); + + throw $exception; + } + + parent::deleteCategory($id); + } catch (\PDOException $e) { + if ($e->getCode() == "23000") { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains footprints."), $category->getNode()->getName())); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains footprints. Please move the footprints to another category."), $category->getNode()->getName())); + + throw $exception; + } else { + throw $e; + } + } + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/FootprintCategory/FootprintCategoryService.php b/src/backend/PartKeepr/FootprintCategory/FootprintCategoryService.php @@ -0,0 +1,9 @@ +<?php +namespace PartKeepr\FootprintCategory; + +use PartKeepr\Category\AbstractCategoryService; + +class FootprintCategoryService extends AbstractCategoryService { + protected $categoryManagerClass = "PartKeepr\FootprintCategory\FootprintCategoryManager"; + protected $categoryClass = "PartKeepr\FootprintCategory\FootprintCategory"; +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/FulltextSearch/FulltextSearch.php b/src/backend/PartKeepr/FulltextSearch/FulltextSearch.php @@ -0,0 +1,94 @@ +<?php +namespace PartKeepr\FulltextSearch; + +use PartKeepr\PartKeepr; + +abstract class FulltextSearch { + + /** + * Creates a new fulltext search based on the given query. + * + * The query can contain different query strings, separated by space. The query returns only results which contain + * all query strings in any fields. + * + * If the query is "100 ohm", it would only consider entities which have both "100" and "ohm", no matter which field + * the value is in. + * + * @param string $query The query to search for + */ + public function __construct ($query) { + $this->query = explode(" ", $query); + } + + /** + * Fires the query and returns the results. + * + * @param none + * @return array An array with all IDs which match the query + */ + public function query () { + return $this->fallbackSearch(); + } + + /** + * A fallback search in case no fulltext search engine is available. This directly queries the database, which is + * slow. + */ + protected function fallbackSearch () { + $qb = PartKeepr::getEM()->createQueryBuilder(); + + $qb ->select("q.id") + ->from($this->getEntityName(), "q") + ->where("1=1"); + + $dqlChunks = array(); + + foreach ($this->query as $id => $queryString) { + $partDqlChunks = array(); + foreach ($this->getFields() as $field) { + $partDqlChunks[] = "LOWER(q." . $field.") LIKE :filter".$id; + } + + $dqlChunks[] = "(".implode(" OR ", $partDqlChunks).")"; + + $qb->setParameter("filter".$id, "%".str_replace("%", "\\%", strtolower($queryString))."%"); + } + + $qb->andWhere(implode(" AND " ,$dqlChunks)); + + $query = $qb->getQuery(); + + + + $result = $query->getArrayResult(); + + if (count($result) > 0) { + $results = array(); + + foreach ($result as $value) { + $results[] = $value["id"]; + } + + return $results; + } else { + return array(0); + } + } + + /** + * Returns the FQDN name of the entity. This needs to be overridden in child classes. + * + * @param none + * @return string the FQDN of the entity to query, e.g. PartKeepr\Part\Part + */ + abstract protected function getEntityName (); + + /** + * Returns the fields in which the fulltext search should search in. + * + * @param none + * @return array An array of field names, e.g. array("name", "description") + */ + abstract protected function getFields (); + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Image/CachedImage.php b/src/backend/PartKeepr/Image/CachedImage.php @@ -0,0 +1,99 @@ +<?php +namespace PartKeepr\Image; + +use PartKeepr\PartKeepr; + +/** + * Represtends a cached image. Cached images are used for scale/resize + * operations, so that the resize/scale operation doesn't need to be done + * every time a scaled/resized image is requested. + * + * @Entity + */ +class CachedImage { + /** + * Specifies the ID of the cached image. + * + * @var integer + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + **/ + private $id; + + /** + * Specifies the ID of the original image + * + * @var integer + * @Column(type="integer") + */ + private $originalId; + + /** + * Specifies the type of the original image. + * + * @var string + * @Column(type="string") + **/ + private $originalType; + + /** + * The cache filename of the image + * + * @var string + * @Column(type="string") + */ + private $cacheFile; + + /** + * Creates a new cache entry for a specific image. + * + * @param Image $image The image to cache + * @param string $cacheFile The file which holds the cached image + */ + public function __construct (Image $image, $cacheFile) { + $this->originalId = (int)$image->getId(); + $this->originalType = $image->getType(); + $this->cacheFile = $cacheFile; + } + + /** + * Returns the cache file + * @return string The cache file including path + */ + public function getCacheFile () { + return $this->cacheFile; + } + + /** + * Removes all caches for a specific image. This is usually called + * when a new version of an image is uploaded. + * + * Automatically calls "flush" on the entity manager. + * + * @param Image $image The image to invalidate + */ + public static function invalidate (Image $image) { + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select(array("c")) + ->from('PartKeepr\Image\CachedImage', 'c') + ->where("c.originalId = :id") + ->andWhere("c.originalType = :type") + ->setParameter("id", $image->getId()) + ->setParameter("type", $image->getType()); + + $query = $qb->getQuery(); + + $bImagesRemoved = false; + + foreach ($query->getResult() as $file) { + unlink($file->getCacheFile()); + PartKeepr::getEM()->remove($file); + $bImagesRemoved = true; + } + + if ($bImagesRemoved) { + PartKeepr::getEM()->flush(); + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Image/Exceptions/InvalidImageTypeException.php b/src/backend/PartKeepr/Image/Exceptions/InvalidImageTypeException.php @@ -0,0 +1,11 @@ +<?php +namespace PartKeepr\Image\Exceptions; + +/** + * Thrown if an invalid type was passed + */ +class InvalidImageTypeException extends \Exception { + public function __construct ($type) { + parent::__construct("The image type $type is unknown."); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Image/Image.php b/src/backend/PartKeepr/Image/Image.php @@ -0,0 +1,227 @@ +<?php +namespace PartKeepr\Image; + +use PartKeepr\PartKeepr, + PartKeepr\UploadedFile\UploadedFile, + PartKeepr\Util\Configuration, + PartKeepr\TempImage\TempImage, + PartKeepr\Image\Exceptions\InvalidImageTypeException; + +/** + * This is only a storage class; actual image rendering is done by the ImageRenderer. + * + * @MappedSuperclass + */ +abstract class Image extends UploadedFile implements RenderableImage { + const IMAGE_ICLOGO = "iclogo"; + const IMAGE_TEMP = "temp"; + const IMAGE_PART = "part"; + const IMAGE_STORAGELOCATION = "storagelocation"; + const IMAGE_FOOTPRINT = "footprint"; + + /** + * Holds the image renderer + * @var object + */ + private $renderer; + + /** + * Constructs a new image object. + * + * @param string $type The type for the image, one of the IMAGE_ constants. + */ + public function __construct ($type) { + parent::__construct(); + $this->setType($type); + } + + /** + * Sets the type of the image. Once the type is set, + * it may not be changed later. + * + * @param string $type The type for the image, one of the IMAGE_ constants. + * @throws InvalidImageTypeException + */ + protected function setType ($type) { + switch ($type) { + case Image::IMAGE_ICLOGO: + case Image::IMAGE_TEMP: + case Image::IMAGE_PART: + case Image::IMAGE_FOOTPRINT: + case Image::IMAGE_STORAGELOCATION: + parent::setType($type); + break; + default: + throw new InvalidImageTypeException($type); + } + } + + /** + * Returns the renderer for image manipulations + * @return object + */ + public function getRenderer () { + if (!$this->renderer instanceof ImageRenderer) { + $this->renderer = new ImageRenderer($this); + } + + return $this->renderer; + } + /** + * Replaces the current image with a new image. + * + * Automatically converts from one format to PNG, + * which is the default when dealing with images + * on the platform. + * + * @param string $path The path to the original image + */ + public function replace ($path) { + parent::replace($path); + + CachedImage::invalidate($this); + } + + /** + * Returns the full image filename including path. + * This is the image where all scale operations take place on. + * + * @param none + * @return string The full image filename including path. + */ + public function getFilename () { + return $this->getFilePath().$this->getPlainFilename().".png"; + } + + /** + * Returns the path to the image. May be overridden by + * subclasses. + * + * @param none + * @return string The path to the image + */ + public function getFilePath () { + return Configuration::getOption( + "partkeepr.images.path", + PartKeepr::getRootDirectory() . "/data/images/") . $this->getType() . "/"; + } + + /** + * Ensures that the image cache dir exists. + */ + public function ensureCachedirExists () { + if (!is_dir(Configuration::getOption("partkeepr.images.cache"))) { + mkdir(Configuration::getOption("partkeepr.images.cache"), 0777, true); + } + } + + /** + * Scales the image to fit within the given size. + * + * @param int $w The width + * @param int $h The height + * @param boolean $padding If true, pad the output image to the given size (transparent background). + * @return string The path to the scaled file + */ + public function fitWithin ($w, $h, $padding = false) { + $this->ensureCachedirExists(); + + if ($padding) { + $pd = "p"; + } else { + $pd = ""; + } + + $outputFile = Configuration::getOption("partkeepr.images.cache").md5($this->getFilename().$w."x".$h."fw".$pd).".png"; + + if (file_exists($outputFile)) { + return $outputFile; + } + + $this->getRenderer()->fitWithin($outputFile, $w, $h, $padding); + + $cachedImage = new CachedImage($this, $outputFile); + PartKeepr::getEM()->persist($cachedImage); + + return $outputFile; + } + + /** + * Convinience method for fitWithin. Automatically pads the image. + * + * @param int $w The width + * @param int $h The height + * @return string The path to the scaled file + */ + public function fitWithinPadding ($w, $h) { + return $this->fitWithin($w, $h); + } + + /** + * Scales the image to fit exactly within the given size. + * + * This method ensures that no blank space is in the output image, + * and that the output image is exactly the width and height specified. + * + * @param string $outputFile The output file + * @param int $w The width + * @param int $h The height + * @return string The path to the scaled file + */ + public function fitWithinExact ($w, $h) { + $this->ensureCachedirExists(); + + $outputFile = Configuration::getOption("partkeepr.images.cache").md5($this->getFilename().$w."x".$h."fwe").".png"; + + if (file_exists($outputFile)) { + return $outputFile; + } + + $this->getRenderer()->fitWithinExact($outputFile, $w, $h); + + $cachedImage = new CachedImage($this, $outputFile); + PartKeepr::getEM()->persist($cachedImage); + + return $outputFile; + } + + /** + * Scales the image to a specific width and height + * + * @param int $w The width + * @param int $h The height + * @return string The path to the scaled file + */ + public function scaleTo ($w, $h) { + $this->ensureCachedirExists(); + + $outputFile = Configuration::getOption("partkeepr.images.cache").md5($this->getFilename().$w."x".$h).".png"; + + if (file_exists($outputFile)) { + return $outputFile; + } + + $this->getRenderer()->scaleTo($outputFile, $w, $h); + + $cachedImage = new CachedImage($this, $outputFile); + PartKeepr::getEM()->persist($cachedImage); + + return $outputFile; + } + + /** + * Replaces the file with a given temporary file. + * @param string $id The temporary id (prefixed with TMP:) + */ + public function replaceFromTemporaryFile ($id) { + if (substr($id, 0, 4) === "TMP:") { + $tmpFileId = str_replace("TMP:", "", $id); + $tmpFile = TempImage::loadById($tmpFileId); + + $this->replace($tmpFile->getFilename()); + $this->setOriginalFilename($tmpFile->getOriginalFilename()); + + } + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Image/ImageRenderer.php b/src/backend/PartKeepr/Image/ImageRenderer.php @@ -0,0 +1,133 @@ +<?php +namespace PartKeepr\Image; + +use PartKeepr\Util\Configuration; + +class ImageRenderer { + private $image = null; + + public function __construct (RenderableImage $image) { + $this->image = $image; + } + + /** + * Renders and outputs the "image not found" image. + * + * Sends the header and immediately outputs the image. + * + * @param int $w Width of the image + * @param int $h Height of the image + */ + public static function outputRenderNotFoundImage ($w, $h) { + $image = imagecreate($w, $h); + $white = imagecolorallocate($image, 255,255,255); + $black = imagecolorallocate($image, 0,0,0); + + header("Content-Type: image/png"); + + $w = $_REQUEST["w"]-1; + $h = $_REQUEST["h"]-1; + imagefill($image, 0,0, $white); + + /* Draw the X */ + imageline($image, 0,0,$w,$h, $black); + imageline($image, $w,0,0,$h, $black); + imagepng($image); + } + + /** + * Scales the image to fit within the given size. + * + * @param string $outputFile The target file + * @param int $w The width + * @param int $h The height + * @param boolean $padding If true, pad the output image to the given size (transparent background). + * @return string The path to the scaled file + */ + public function fitWithin ($outputFile, $w, $h, $padding = false) { + $image = new \Imagick(); + $image->readImage($this->image->getFilename()); + + $sourceAspectRatio = $image->getImageWidth() / $image->getImageHeight(); + $targetAspectRatio = $w / $h; + + $filter = \Imagick::FILTER_UNDEFINED; + $blur = 1; + + $targetHeight = $h; + $targetWidth = $w; + + if ($sourceAspectRatio < $targetAspectRatio) { + $targetWidth = $h * $sourceAspectRatio; + $image->resizeImage($h * $sourceAspectRatio, $h, $filter, $blur); + } else { + $targetHeight = $w / $sourceAspectRatio; + $image->resizeImage($w, $w / $sourceAspectRatio, $filter, $blur); + } + + if ($padding) { + $posX = intval(($w - $targetWidth) / 2); + $posY = intval(($h - $targetHeight) / 2); + + $image->extentImage($w, $h,-$posX, -$posY); + } + + $image->writeImage($outputFile); + + return $outputFile; + } + + /** + * Scales the image to fit exactly within the given size. + * + * This method ensures that no blank space is in the output image, + * and that the output image is exactly the width and height specified. + * + * @param string $outputFile The output file + * @param int $w The width + * @param int $h The height + * @return string The path to the scaled file + */ + public function fitWithinExact ($outputFile, $w, $h) { + $image = new \Imagick(); + $image->readImage($this->image->getFilename()); + + $sourceAspectRatio = $image->getImageWidth() / $image->getImageHeight(); + $targetAspectRatio = $w / $h; + + $filter = \Imagick::FILTER_UNDEFINED; + $blur = 1; + + if ($sourceAspectRatio < $targetAspectRatio) { + $image->resizeImage($w, $w / $sourceAspectRatio, $filter, $blur); + } else { + $image->resizeImage($h * $sourceAspectRatio, $h, $filter, $blur); + } + + $offsetX = intval(($image->getImageWidth() - $w)/2); + $offsetY = intval(($image->getImageHeight() - $h)/2); + + $image = $image->getImageRegion($w, $h, $offsetX, $offsetY); + + $image->writeImage($outputFile); + + return $outputFile; + } + + /** + * Scales the image to a specific width and height + * + * @param string $outputFile The output file + * @param int $w The width + * @param int $h The height + * @return string The path to the scaled file + */ + public function scaleTo ($outputFile, $w, $h) { + $image = new \Imagick(); + $image->readImage($this->image->getFilename()); + $image->adaptiveResizeImage($w, $h); + $image->writeImage($outputFile); + + return $outputFile; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Image/RenderableImage.php b/src/backend/PartKeepr/Image/RenderableImage.php @@ -0,0 +1,16 @@ +<?php +namespace PartKeepr\Image; + +/** + * Interface for any image which needs to be rendered. + */ +interface RenderableImage { + /** + * Returns the full image filename including path. + * This is the image where all scale operations take place on. + * + * @param none + * @return string The full image filename including path. + */ + public function getFilename (); +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Logger/Logger.php b/src/backend/PartKeepr/Logger/Logger.php @@ -0,0 +1,121 @@ +<?php +namespace PartKeepr\Logger; + +/** + * This class implements a simple logging mechanism. + * + * Might be replaced with some more advanced logging framework, but it serves its purpose for now. + */ +use PartKeepr\Util\Configuration; + +class Logger { + /** + * Loglevel "debug" + * + * You want to use this loglevel for debugging messages. + * @var string + */ + const LOGLEVEL_DEBUG = "debug"; + + /** + * Loglevel "info" + * + * You want to use this loglevel for informational messages where the program flow can continue normally and no + * impacts occur. + * + * @var string + */ + const LOGLEVEL_INFO = "info"; + + /** + * Loglevel "warning" + * + * You want to use this loglevel for messages where program flow can continue normally, but a minor + * impact can occur. + * + * @var string + */ + const LOGLEVEL_WARNING = "warning"; + + /** + * Loglevel "error" + * + * You want to use this loglevel for messages where program flow could be interrupted and major impacts occur. + * + * @var string + */ + const LOGLEVEL_ERROR = "error"; + + /** + * Loglevel "critical" + * + * You want to use this loglevel for messages where program flow could be interrupted and major impacts occur. + * + * @var string + */ + const LOGLEVEL_CRITICAL = "critical"; + + /** + * Logs a message. + * + * @param string $message The message to log + * @param string $severity One of the Logger::LOGLEVEL_* constants + */ + public static function log ($message, $severity = Logger::LOGLEVEL_INFO) { + if (Configuration::getOption("partkeepr.logger.enable", false) === false) { + // No logging wanted + return; + } + + $logFormat = "[%-19s] [%-8s] %s"; + + $outputFile = Configuration::getOption("partkeepr.logger.outputfile", sys_get_temp_dir() . "/partkeepr.log"); + $fp = fopen($outputFile, "a"); + + $date = date("Y-m-d H:i:s"); + + fputs($fp, sprintf($logFormat, $date, $severity, $message)."\n"); + + fclose($fp); + } + + /** + * Logs a message with the Logger::LOGLEVEL_DEBUG severity. + * @param string $message + */ + public static function logDebug ($message) { + self::log($message, Logger::LOGLEVEL_DEBUG); + } + + /** + * Logs a message with the Logger::LOGLEVEL_INFO severity. + * @param string $message + */ + public static function logInfo ($message) { + self::log($message, Logger::LOGLEVEL_INFO); + } + + /** + * Logs a message with the Logger::LOGLEVEL_WARNING severity. + * @param string $message + */ + public static function logWarning ($message) { + self::log($message, Logger::LOGLEVEL_WARNING); + } + + /** + * Logs a message with the Logger::LOGLEVEL_ERROR severity. + * @param string $message + */ + public static function logError ($message) { + self::log($message, Logger::LOGLEVEL_ERROR); + } + + /** + * Logs a message with the Logger::LOGLEVEL_CRITICAL severity. + * @param string $message + */ + public static function logCritical ($message) { + self::log($message, Logger::LOGLEVEL_CRITICAL); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manager/AbstractManager.php b/src/backend/PartKeepr/Manager/AbstractManager.php @@ -0,0 +1,230 @@ +<?php +namespace PartKeepr\Manager; + +use PartKeepr\Util\Singleton, + PartKeepr\PartKeepr, + Doctrine\ORM\QueryBuilder, + Doctrine\ORM\Query, + PartKeepr\Manager\Exceptions\EntityInUseException; + +/** + * The AbstractManager is a very basic helper which + * implements the mostly used operations on entities: + * + * - Create + * - Delete + * - List + * + */ +abstract class AbstractManager extends Singleton { + /** + * Returns the FQCN for the target entity to operate on. + * + * Needs to be implemented by the parent class. + * + * @return string The FQCN, e.g. PartKeepr\Part + */ + abstract public function getEntityName (); + + /** + * Returns all fields which need to appear in the getList ResultSet. + * + * This should include all fields required by the frontend. + * + * @return array An array of all fields which should be returned + */ + abstract public function getQueryFields (); + + /** + * Returns the default sort field + * + * @return string The default sort field + */ + abstract public function getDefaultSortField (); + + /** + * Loads an entity by id + * + * @param int $id The entity id + */ + public function getEntity ($id) { + return call_user_func($this->getEntityName()."::loadById", $id); + } + + /** + * Removes a specific entity from the system + * @param int $id + * @throws EntityInUseException Is thrown when the entity is in use + */ + public function deleteEntity ($id) { + $entity = $this->getEntity($id); + + try { + PartKeepr::getEM()->remove($entity); + PartKeepr::getEM()->flush(); + } catch (\PDOException $e) { + if ($e->getCode() == "23000") { + throw new EntityInUseException($entity); + } + } + } + + /** + * Creates a new entity from an array of parameters + * @param array $parameters An array which gets passed to the deserialize method + */ + public function createEntity ($parameters) { + $class = $this->getEntityName(); + $entity = new $class; + $entity->deserialize($parameters); + + PartKeepr::getEM()->persist($entity); + PartKeepr::getEM()->flush(); + + return $entity; + } + + /** + * Returns a list of entities. + * + * @param ManagerFilter $filter The filter settings for this query + */ + public function getList (ManagerFilter $filter) { + $qb = PartKeepr::getEM()->createQueryBuilder(); + + $qb->select("COUNT(q.id)")->from($this->getEntityName(),"q"); + + $this->applyFiltering($qb, $filter); + $this->applyCustomQuery($qb, $filter); + + $totalQuery = $qb->getQuery(); + + $this->applyResultFields($qb, $filter); + $this->applyPagination($qb, $filter); + $this->applySorting($qb, $filter); + + $query = $qb->getQuery(); + + return array("data" => $this->getResult($query), "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Processes the result after it was retrieved. In the default configuration, it returns an array result, or + * if no query fields are specified, it tries to serialize all objects. + */ + protected function getResult (Query $query) { + if (count($this->getQueryFields()) == 0) { + $aSerializedResult = array(); + foreach ($query->getResult() as $result) { + $aSerializedResult[] = $result->serialize(); + } + + return $aSerializedResult; + } else { + return $query->getArrayResult(); + } + } + + /** + * Applies the result fields to the query. + * + * The result fields can be prefixed with the table alias or not; if not prefixed, it is assumed that we'll be + * using the specified entity FQCN. + * + * Note that the base name will be always "q", so avoid "q" as alias for joined tables. + * + * @param QueryBuilder $qb The query builder + * @param ManagerFilter $filter The query filter + */ + protected function applyResultFields (QueryBuilder $qb, ManagerFilter $filter) { + if (count($this->getQueryFields()) == 0) { + $qb->select("q"); + } else { + // Prepend a prefix to each field + $aQueryFields = array(); + foreach ($this->getQueryFields() as $field) { + + if (strpos($field, ".") === false) { + // The field is not prefixed, prepend the q. prefix + $aQueryFields[] = "q.".$field; + } else { + // Use as-is + $aQueryFields[] = $field; + } + } + + $qb->select($aQueryFields); + } + } + + /** + * Applies filtering to the query and calls back the custom filtering function, if required. + * + * @param QueryBuilder $qb The query builder + * @param ManagerFilter $filter The query filter + */ + protected function applyFiltering (QueryBuilder $qb, ManagerFilter $filter) { + if ($filter->getFilter() !== null && $filter->getFilterField() !== null) { + $aOrWhereFields = array(); + + if (is_array($filter->getFilterField())) { + foreach ($filter->getFilterField() as $field) { + $aOrWhereFields[] = "LOWER(q.".$field.") LIKE :filter"; + } + } else { + $aOrWhereFields[] = "LOWER(q.".$filter->getFilterField().") LIKE :filter"; + } + + foreach ($aOrWhereFields as $or) { + $qb->orWhere($or); + } + + $qb->setParameter("filter", "%".strtolower($filter->getFilter())."%"); + } + + if ($filter->getFilterCallback() !== null) { + call_user_func($filter->getFilterCallback(), $qb); + } + } + + + /** + * Applies a custom query to the QueryBuilder + * + * @param QueryBuilder $qb The query builder + * @param ManagerFilter $filter The query filter + */ + protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { + + } + + /** + * Applies pagination to the query + * + * @param QueryBuilder $qb The query builder + * @param ManagerFilter $filter The query filter + */ + protected function applyPagination (QueryBuilder $qb, ManagerFilter $filter) { + if ($filter->getStart() !== null && $filter->getLimit() !== null) { + $qb->setFirstResult($filter->getStart()); + } + + if ($filter->getLimit() !== null) { + $qb->setMaxResults($filter->getLimit()); + } + } + + /** + * Applies record sorting + * + * @param QueryBuilder $qb The query builder + * @param ManagerFilter $filter The query filter + */ + protected function applySorting (QueryBuilder $qb, ManagerFilter $filter) { + foreach ($filter->getSorters() as $sorter) { + if ($sorter->getSortField() !== null && $sorter->getSortField() != "q.") { + $qb->addOrderBy($sorter->getSortField(), $sorter->getSortDirection()); + } + } + } +} + \ No newline at end of file diff --git a/src/backend/PartKeepr/Manager/Exceptions/EntityInUseException.php b/src/backend/PartKeepr/Manager/Exceptions/EntityInUseException.php @@ -0,0 +1,31 @@ +<?php +namespace PartKeepr\Manager\Exceptions; + +/** + * This exception is thrown when an entity should be deleted, but is in use by other entities. + * @author felicitus + */ +class EntityInUseException extends \Exception { + + /** + * The entity + * @var BaseEntity + */ + private $entity; + + /** + * Constructs the exception + * @param BaseEntity $entity + */ + public function __construct (\PartKeepr\Util\BaseEntity $entity) { + parent::__construct(sprintf("Entity %s is referenced by other entities, can't delete", get_class($entity))); + $this->entity = $entity; + } + + /** + * Returns the entity which caused the error + */ + public function getEntity () { + return $this->entity; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manager/ManagerFilter.php b/src/backend/PartKeepr/Manager/ManagerFilter.php @@ -0,0 +1,196 @@ +<?php +namespace PartKeepr\Manager; + +use PartKeepr\Service\Service; + +class ManagerFilter { + /** + * Specifies the record index at which to start + * @var integer + */ + protected $start = 0; + + /** + * Specifies the number of records to retrieve + * @var integer + */ + protected $limit = null; + + /** + * Specifies a string to filter for. Can either be a string + * or null if no filter is wanted + * @var string + */ + protected $filter = null; + + /** + * Specifies the field (or a list of fields) to apply the filter on + * @var mixed null if disabled, a string for a single field or an array of fields + */ + protected $filterField = null; + + /** + * Specifies the fields to sort by + * @var array + */ + protected $sorters = array(); + + /** + * A callback which is called when creating the filter + * @var function The callback + */ + protected $callback = null; + + /** + * Sets the start position + * @param int $start + */ + public function setStart ($start) { + $this->start = intval($start); + } + + /** + * Returns the start position + * @return int + */ + public function getStart () { + if ($this->start === null) { + return 0; + } else { + return $this->start; + } + } + + /** + * Sets the number of records to retrieve + * @param mixed $limit Either a positive integer, or null/-1 for no limit + */ + public function setLimit ($limit) { + if ($limit === null || $limit == -1) { + $this->limit = null; + } else { + $this->limit = intval($limit); + } + } + + /** + * Returns the number of records to retrieve + * @return int + */ + public function getLimit () { + return $this->limit; + } + + /** + * Sets the sorters for this filter. + * + * @param array $sorters An array of Sorter instances + */ + public function setSorters (array $sorters) { + // Make sure that each sorter is an instance of the Sorter class. + foreach ($sorters as $sorter) { + if (!($sorter instanceof Sorter)) { + throw new InvalidArgumentException("The passed sorters needs to be an array of Sorter instances"); + } + } + + $this->sorters = $sorters; + } + + /** + * Returns the sorters for this filter. + * @return array An array of Sorter instances + */ + public function getSorters () { + return $this->sorters; + } + + /** + * Sets the filter. Specify null if no filter is wanted. + * @param mixed $filter A string to filter for, or null to disable + */ + public function setFilter ($filter) { + $this->filter = $filter; + } + + /** + * Returns the filter. + * @return mixed Either a string to filter for, or null if disabled + */ + public function getFilter () { + return $this->filter; + } + + /** + * Sets the field(s) to filter for. + * + * If multiple fields are specified, they will be combined using an "OR" clause. + * + * @param mixed $field Either null to disable, a single string to specify a field, or an array of string fields + */ + public function setFilterField ($field) { + $this->filterField = $field; + } + + /** + * Returns the field(s) to filter for + * @return mixed See setFilterField + */ + public function getFilterField () { + return $this->filterField; + } + + /** + * Sets the filter callback + * @param function $callback A function which is called when creating a filter. The callback function receives the + * query builder as first argument. + */ + public function setFilterCallback ($callback) { + $this->callback = $callback; + } + + /** + * Returns the filter callback + * @return function The callback function + */ + public function getFilterCallback () { + return $this->callback; + } + + /** + * Constructs a new filter set. + * + * If a service is passed, the constructor automatically extracts the parameters from the service + * + * @todo Document which parameters we have + * + * @param Service $service A service to extract the information from, or null + */ + public function __construct (Service $service = null) { + if (is_object($service)) { + if ($service->hasParameter("start")) { + $this->setStart($service->getParameter("start", null)); + } + + if ($service->hasParameter("limit")) { + $this->setLimit($service->getParameter("limit", null)); + } + + if ($service->hasParameter("sort")) { + $tmp = json_decode($service->getParameter("sort"), true); + + $aSorters = array(); + + foreach ($tmp as $key => $sortParam) { + $aSorters[] = new Sorter("q.".$sortParam["property"], $sortParam["direction"]); + } + + $this->setSorters($aSorters); + } + + if ($service->hasParameter("query")) { + $this->setFilter($service->getParameter("query")); + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manager/Sorter.php b/src/backend/PartKeepr/Manager/Sorter.php @@ -0,0 +1,79 @@ +<?php +namespace PartKeepr\Manager; + +/** + * Represents a sorter, which is used with the ManagerFilter class. + * + * This allows the developer to specify multiple sorters. One sorter contains a sort field and a sort direction. + */ +class Sorter { + /** + * The field to sort by + * @var string + */ + private $sortField = null; + + /** + * The direction to sort by + * @var string + */ + private $sortDirection = null; + + /** + * Constructs a new sorter. + * + * @param string $field The field to sort by + * @param string $direction The direction, either "asc" or "desc" + */ + public function __construct ($field = null, $direction = null) { + if ($field !== null) { + $this->setSortField($field); + } + + if ($direction !== null) { + $this->setSortDirection($direction); + } + } + + /** + * Sets the sort field for this sorter + * @param string $field The field to sort by + */ + public function setSortField ($field) { + $this->sortField = $field; + } + + /** + * Sets the sort direction for this sorter + * @param string $direction Either "asc" or "desc" + */ + public function setSortDirection ($direction) { + switch (strtolower($direction)) { + case "desc": + case "d": + $this->sortDirection = "desc"; + break; + case "asc": + case "a": + default: + $this->sortDirection = "asc"; + break; + } + } + + /** + * Returns the sort field for this sorter + * @return string The field name + */ + public function getSortField () { + return $this->sortField; + } + + /** + * Returns the sort order for this sorter + * @return string Either "asc" or "desc" + */ + public function getSortDirection () { + return $this->sortDirection; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manufacturer/Manufacturer.php b/src/backend/PartKeepr/Manufacturer/Manufacturer.php @@ -0,0 +1,250 @@ +<?php +namespace PartKeepr\Manufacturer; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr; + +/** + * Represents a manufacturer + * @Entity **/ +class Manufacturer extends BaseEntity implements Serializable, Deserializable { + /** + * The name of the manufacturer + * @Column(type="string",unique=true) + * @var string + */ + private $name; + + /** + * The address of the manufacturer + * @Column(type="text",nullable=true) + * @var string + */ + private $address; + + /** + * The URL + * @Column(type="string",nullable=true) + * @var string + */ + private $url; + + /** + * The email + * @Column(type="string",nullable=true) + * @var string + */ + private $email; + + /** + * The comment + * @Column(type="text",nullable=true) + * @var string + */ + private $comment; + + /** + * The phone number + * @Column(type="string",nullable=true) + * @var string + */ + private $phone; + + /** + * The fax number + * @Column(type="string",nullable=true) + * @var string + */ + private $fax; + + /** + * All ic logos of this manufacturer + * @OneToMany(targetEntity="PartKeepr\Manufacturer\ManufacturerICLogo",mappedBy="manufacturer",cascade={"persist", "remove"}) + */ + private $icLogos; + + /** + * Creates a new manufacturer instance + */ + public function __construct () { + $this->icLogos = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Sets the name + * @param string $name The name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name + * @return string The name + */ + public function getName () { + return $this->name; + } + + /** + * Sets the phone number + * @param string $phone The phone number + */ + public function setPhone ($phone) { + $this->phone = $phone; + } + + /** + * Returns the phone number + * @return string The phone number + */ + public function getPhone () { + return $this->phone; + } + + /** + * Sets the fax number + * @param string $fax The fax number + */ + public function setFax ($fax) { + $this->fax = $fax; + } + + /** + * Returns the fax number + * @return string The fax number + */ + public function getFax () { + return $this->fax; + } + + /** + * Sets the address + * @param string $address The address + */ + public function setAddress ($address) { + $this->address = $address; + } + + /** + * Returns the address + * @return string The address + */ + public function getAddress () { + return $this->address; + } + + /** + * Sets the comment + * @param string $comment The comment + */ + public function setComment ($comment) { + $this->comment = $comment; + } + + /** + * Returns the comment + * @return string The comment + */ + public function getComment () { + return $this->comment; + } + + /** + * Sets the email + * @param string $email The email + */ + public function setEmail ($email) { + $this->email = $email; + } + + /** + * Returns the email + * @return string The email + */ + public function getEmail () { + return $this->email; + } + + /** + * Sets the URL + * @param string $url The URL + */ + public function setURL ($url) { + $this->url = $url; + } + + /** + * Returns the URL + * @return string The url + */ + public function getURL () { + return $this->url; + } + + /** + * Returns the ic logos + * @return ArrayCollection The array with all ic logos + */ + public function getICLogos () { + return $this->icLogos; + } + + /** + * Returns this manufacturer in serialized form + * @return array The serialized manufacturer + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "url" => $this->getURL(), + "address" => $this->getAddress(), + "email" => $this->getEmail(), + "comment" => $this->getComment(), + "phone" => $this->getPhone(), + "fax" => $this->getFax(), + "iclogos" => $this->serializeChildren($this->getICLogos()) + ); + } + + /** + * Deserializes the manufacturer + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "url": + $this->setURL($value); + break; + case "comment": + $this->setComment($value); + break; + case "email": + $this->setEmail($value); + break; + case "fax": + $this->setFax($value); + break; + case "phone": + $this->setPhone($value); + break; + case "address": + $this->setAddress($value); + break; + case "iclogos": + $this->deserializeChildren($value, $this->getICLogos(), "PartKeepr\Manufacturer\ManufacturerICLogo"); + foreach ($this->getICLogos() as $iclogo) { + $iclogo->setManufacturer($this); + } + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manufacturer/ManufacturerICLogo.php b/src/backend/PartKeepr/Manufacturer/ManufacturerICLogo.php @@ -0,0 +1,63 @@ +<?php +namespace PartKeepr\Manufacturer; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Image\Image; + +/** + * Holds a manufacturer IC logo + * @Entity + **/ +class ManufacturerICLogo extends Image implements Serializable, Deserializable { + /** + * The manufacturer object + * @ManyToOne(targetEntity="PartKeepr\Manufacturer\Manufacturer") + * @var Manufacturer + */ + private $manufacturer = null; + + /** + * Creates a new IC logo instance + */ + public function __construct () { + parent::__construct(Image::IMAGE_ICLOGO); + } + + /** + * Sets the manufacturer + * @param Manufacturer $manufacturer The manufacturer to set + */ + public function setManufacturer (Manufacturer $manufacturer) { + $this->manufacturer = $manufacturer; + } + + /** + * Returns the manufacturer + * @return Manufacturer the manufacturer + */ + public function getManufacturer () { + return $this->manufacturer; + } + + /** + * + * Serializes this ic logo + * @return array The serialized ic logo + */ + public function serialize () { + return array("id" => $this->getId(), "manufacturer_id" => $this->getManufacturer()->getId()); + } + + /** + * Deserializes the iclogo + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + if (array_key_exists("id", $parameters)) { + if (substr($parameters["id"], 0, 4) === "TMP:") { + $this->replaceFromTemporaryFile($parameters["id"]); + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manufacturer/ManufacturerManager.php b/src/backend/PartKeepr/Manufacturer/ManufacturerManager.php @@ -0,0 +1,104 @@ +<?php +namespace PartKeepr\Manufacturer; + +use PartKeepr\Util\Singleton, + PartKeepr\Manufacturer\Manufacturer, + PartKeepr\PartKeepr, + PartKeepr\Category\CategoryManager, + PartKeepr\Manufacturer\Exceptions\ManufacturerNotFoundException; + +class ManufacturerManager extends Singleton { + /** + * Returns a list of manufacturers. + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter A string to filter the manufacturer's name by, default empty + */ + public function getManufacturers ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st.id, st.name, st.url, st.email, st.comment, st.address")->from("PartKeepr\Manufacturer\Manufacturer","st"); + + if ($filter != "") { + $qb = $qb->where("LOWER(st.name) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\Manufacturer\Manufacturer","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Adds a new manufacturer by name + * + * @param string $name The manufacturer name + */ + public function addManufacturer ($name) { + $manufacturer = new Manufacturer(); + $manufacturer->setName($name); + + PartKeepr::getEM()->persist($manufacturer); + PartKeepr::getEM()->flush(); + + return $manufacturer; + } + + /** + * Loads a manufacturer by id + * + * @param int $id The manufacturer id + */ + public function getManufacturer ($id) { + return Manufacturer::loadById($id); + } + + /** + * Deletes the manufacturer by id + * @param int $id The manufacturer's id + */ + public function deleteManufacturer ($id) { + $manufacturer = Manufacturer::loadById($id); + + PartKeepr::getEM()->remove($manufacturer); + PartKeepr::getEM()->flush(); + } + + /** + * Retrieves a manufacturer by its name. + * + * @param string $name The name of the manufacturer to retrieve + * @throws Doctrine\ORM\NoResultException If the manufacturer was not found + */ + public function getManufacturerByName ($name) { + $dql = "SELECT m FROM PartKeepr\Manufacturer\Manufacturer m WHERE m.name = :name"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $name); + + return $query->getSingleResult(); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Manufacturer/ManufacturerService.php b/src/backend/PartKeepr/Manufacturer/ManufacturerService.php @@ -0,0 +1,82 @@ +<?php +namespace PartKeepr\Manufacturer; + +use PartKeepr\Service\RestfulService; + +use PartKeepr\Service\Service, + PartKeepr\Part\PartManager, + PartKeepr\Stock\StockEntry, + PartKeepr\PartKeepr, + PartKeepr\Session\SessionManager; + +class ManufacturerService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return array("data" => ManufacturerManager::getInstance()->getManufacturer($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "name", + "direction" => "ASC"); + } + return ManufacturerManager::getInstance()->getManufacturers( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $this->requireParameter("name"); + + $manufacturer = new Manufacturer; + $manufacturer->deserialize($this->getParameters()); + + PartKeepr::getEM()->persist($manufacturer); + PartKeepr::getEM()->flush(); + + return array("data" => $manufacturer->serialize()); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + $manufacturer = ManufacturerManager::getInstance()->getManufacturer($this->getParameter("id")); + $manufacturer->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $manufacturer->serialize()); + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + $this->requireParameter("id"); + + ManufacturerManager::getInstance()->deleteManufacturer($this->getParameter("id")); + + return array("data" => null); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/ManufacturerICLogo/ManufacturerICLogoManager.php b/src/backend/PartKeepr/ManufacturerICLogo/ManufacturerICLogoManager.php @@ -0,0 +1,65 @@ +<?php +namespace PartKeepr\ManufacturerICLogo; + +use PartKeepr\Util\Singleton, + PartKeepr\Manufacturer\Manufacturer, + PartKeepr\PartKeepr, + PartKeepr\Manufacturer\Exceptions\ManufacturerNotFoundException; + +class ManufacturerICLogoManager extends Singleton { + /** + * Returns a list of manufacturer ic logos. + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter The manufacturer id + */ + public function getManufacturerICLogos ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st.id, maf.id AS manufacturer_id")->from("PartKeepr\Manufacturer\ManufacturerICLogo","st") + ->leftJoin('st.manufacturer', "maf"); + + 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("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\Manufacturer\ManufacturerICLogo","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("st.manufacturer = :manufacturer"); + $totalQueryBuilder->setParameter("manufacturer", $manufacturer); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Returns a manufacturer ic logo by id + * @param int $id The manufacturer ic logo id + */ + public function getManufacturerICLogo ($id) { + return ManufacturerICLogo::loadById($id); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/ManufacturerICLogo/ManufacturerICLogoService.php b/src/backend/PartKeepr/ManufacturerICLogo/ManufacturerICLogoService.php @@ -0,0 +1,101 @@ +<?php +namespace PartKeepr\ManufacturerICLogo; + +use PartKeepr\Manufacturer\ManufacturerICLogo, + PartKeepr\TempImage\TempImage, + PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Manufacturer\Manufacturer, + PartKeepr\Session\SessionManager; + +class ManufacturerICLogoService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return ManufacturerICLogoManager::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"]; + } + } + } + } + } + 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); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + 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()); + $image->setOriginalFilename($tmpImage->getOriginalFilename()); + PartKeepr::getEM()->persist($image); + PartKeepr::getEM()->flush(); + + return $image->serialize(); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + 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/Part/Exceptions/CategoryNotAssignedException.php b/src/backend/PartKeepr/Part/Exceptions/CategoryNotAssignedException.php @@ -0,0 +1,20 @@ +<?php +namespace PartKeepr\Part\Exceptions; + +use PartKeepr\PartKeepr, + PartKeepr\Util\SerializableException, + PartKeepr\Part\Part; + +/** + * This exception is thrown when a part hasn't got a category assigned + */ +class CategoryNotAssignedException extends SerializableException { + + /** + * Constructs the exception + * @param BaseEntity $entity + */ + public function __construct (Part $part) { + parent::__construct(PartKeepr::i18n("Part %s has no category assigned", $part)); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/Exceptions/StorageLocationNotAssignedException.php b/src/backend/PartKeepr/Part/Exceptions/StorageLocationNotAssignedException.php @@ -0,0 +1,19 @@ +<?php +namespace PartKeepr\Part\Exceptions; + +use PartKeepr\PartKeepr, + PartKeepr\Util\SerializableException; + +/** + * This exception is thrown when a part hasn't got a storage location assigned + */ +class StorageLocationNotAssignedException extends SerializableException { + + /** + * Constructs the exception + * @param BaseEntity $entity + */ + public function __construct () { + parent::__construct(PartKeepr::i18n("No storage location assigned")); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/Part.php b/src/backend/PartKeepr/Part/Part.php @@ -0,0 +1,640 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\StorageLocation\StorageLocation, + PartKeepr\Footprint\Footprint, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Util\Deserializable, + PartKeepr\PartCategory\PartCategory, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr, + PartKeepr\Part\Exceptions\CategoryNotAssignedException, + PartKeepr\Util\Exceptions\OutOfRangeException, + PartKeepr\Part\Exceptions\StorageLocationNotAssignedException; + + +/** + * Represents a part in the database. The heart of our project. Handle with care! + * + * @Entity @HasLifecycleCallbacks + */ +class Part extends BaseEntity implements Serializable, Deserializable { + /** + * The category of the part + * @ManyToOne(targetEntity="PartKeepr\PartCategory\PartCategory") + * @var Category + */ + private $category; + + /** + * The part's name + * @Column + * @var string + */ + private $name; + + /** + * The part's short description + * @Column(type="string",nullable=true) + * @var string + */ + private $description; + + /** + * The footprint of this part + * @ManyToOne(targetEntity="PartKeepr\Footprint\Footprint") + * @var Footprint + */ + private $footprint; + + /** + * The unit in which the part's "amount" is calculated. This is necessary to count parts + * in "pieces", "meters" or "grams". + * @ManyToOne(targetEntity="PartKeepr\Part\PartUnit") + * @var PartUnit + */ + private $partUnit; + + /** + * Defines the storage location of this part + * @ManyToOne(targetEntity="PartKeepr\StorageLocation\StorageLocation") + * @var StorageLocation + */ + private $storageLocation; + + /** + * Holds the manufacturers which can manufacture this part + * @OneToMany(targetEntity="PartKeepr\Part\PartManufacturer",mappedBy="part",cascade={"persist", "remove"}) + * @var ArrayCollection + */ + private $manufacturers; + + /** + * Holds the distributors from where we can buy the part + * @OneToMany(targetEntity="PartKeepr\Part\PartDistributor",mappedBy="part",cascade={"persist", "remove"}) + * @var ArrayCollection + */ + private $distributors; + + /** + * Holds the part images + * @OneToMany(targetEntity="PartKeepr\Part\PartImage",mappedBy="part",cascade={"persist", "remove"}) + * @var PartImage + */ + private $images; + + /** + * Holds the part attachments + * @OneToMany(targetEntity="PartKeepr\Part\PartAttachment",mappedBy="part",cascade={"persist", "remove"}) + * @var PartAttachment + */ + private $attachments; + + /** + * The comment for this part + * @Column(type="text") + */ + private $comment = ""; + + /** + * The stock level. Note that this is a cached value, because it makes our summary queries easier. + * @todo It would be nice if we could get rid of that. + * @Column(type="integer") + * @var integer + */ + private $stockLevel = 0; + + /** + * The minimum stock level for this part. If we run out of this part (e.g. stockLevel < minStockLevel), + * we can see that in the system and re-order parts. + * + * @Column(type="integer") + * @var integer + */ + private $minStockLevel = 0; + + /** + * The average price for the part. Note that this is a cached value. + * + * @todo It would be nice if we could get rid of that + * @Column(type="decimal",precision=13,scale=4,nullable=true) + * @var float + */ + private $averagePrice = null; + + /** + * The stock level history + * @OneToMany(targetEntity="PartKeepr\Stock\StockEntry",mappedBy="part",cascade={"persist", "remove"}) + * @var ArrayCollection + */ + private $stockLevels; + + /** + * The parameters for this part + * @OneToMany(targetEntity="PartKeepr\PartParameter\PartParameter",mappedBy="part",cascade={"persist", "remove"}) + * @var ArrayCollection + */ + private $parameters; + + /** + * The part status for this part + * @Column(type="string",nullable=true) + * @var string + */ + private $status; + + /** + * Defines if the part needs review + * @Column(type="boolean") + * @var boolean + */ + private $needsReview; + + /** + * The create date+time for this part + * @Column(type="datetime",nullable=true) + * @var \DateTime + */ + private $createDate; + + /** + * @OneToMany(targetEntity="PartKeepr\Project\Project", mappedBy="part") + **/ + private $projects; + + /** + * The internal part number + * @Column(type="string",nullable=true) + * @var string + */ + private $internalPartNumber; + + public function __construct () { + $this->distributors = new \Doctrine\Common\Collections\ArrayCollection(); + $this->manufacturers = new \Doctrine\Common\Collections\ArrayCollection(); + $this->parameters = new \Doctrine\Common\Collections\ArrayCollection(); + $this->images = new \Doctrine\Common\Collections\ArrayCollection(); + $this->attachments = new \Doctrine\Common\Collections\ArrayCollection(); + $this->setCreateDate(new \DateTime()); + $this->setReviewFlag(false); + } + + /** + * Sets the name for this part + * @param string $name The part's name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name of this part + * @return string The part name + */ + public function getName () { + return $this->name; + } + + /** + * Sets the internal part number for this part + * @param string $partnumber + */ + public function setInternalPartNumber ($partNumber) { + $this->internalPartNumber = $partNumber; + } + + /** + * Returns the internal part number for this part + * @return string the internal part number + */ + public function getInternalPartNumber () { + return $this->internalPartNumber; + } + + /** + * Sets the description for this part + * @param string $description The part's short description + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the short description of this part + * @return string The part description + */ + public function getDescription () { + return $this->description; + } + + /** + * Sets the part unit + * + * @param PartUnit $partUnit The part unit object to set + * @return nothing + */ + public function setPartUnit (PartUnit $partUnit) { + $this->partUnit = $partUnit; + } + + /** + * Returns the part unit + * + * @param none + * @return PartUnit The part unit object + */ + public function getPartUnit () { + return $this->partUnit; + } + + /** + * Sets the average price for this unit + * @todo Is this actually used? + * @param float $price The price to set + */ + public function setAveragePrice ($price) { + $this->averagePrice = $price; + } + + /** + * Updates the internal stock level from the stock history + */ + public function updateStockLevel () { + $this->stockLevel = $this->getStockLevel(); + } + + /** + * Sets the review flag + * @param boolean $bReview True if the part needs review, false otherwise + */ + public function setReviewFlag ($bReview) { + $this->needsReview = $bReview; + } + + /** + * Returns the review flag + * @return boolean True if the part needs review, false otherwise + */ + public function getReviewFlag () { + return $this->needsReview; + } + + /** + * Set the minimum stock level for this part + * + * Only positive values are allowed. + * + * @param int $minStockLevel A minimum stock level, only values >= 0 are allowed. + * @throws \PartKeepr\Util\Exceptions\OutOfRangeException If the passed stock level is not in range (>=0) + */ + public function setMinStockLevel ($minStockLevel) { + $minStockLevel = intval($minStockLevel); + + if ($minStockLevel < 0) { + $exception = new OutOfRangeException(PartKeepr::i18n("Minimum Stock Level is out of range")); + $exception->setDetail(PartKeepr::i18n("The minimum stock level must be 0 or higher")); + throw $exception; + } + $this->minStockLevel = $minStockLevel; + } + + /** + * Sets the category for this part + * @param \PartKeepr\PartCategory\PartCategory $category The category + */ + public function setCategory (PartCategory $category) { + $this->category = $category; + } + + /** + * Returns the assigned category + * @return \PartKeepr\PartCategory\PartCategory + */ + public function getCategory () { + return $this->category; + } + + /** + * Returns all projects this part is used + * @return ArrayCollection the projects + */ + public function getProjects () { + return $this->projects; + } + + /** + * Sets the storage location for this part + * @param \PartKeepr\StorageLocation\StorageLocation $storageLocation The storage location + */ + public function setStorageLocation (StorageLocation $storageLocation) { + $this->storageLocation = $storageLocation; + } + + /** + * Returns the storage location for this part + * @return \PartKeepr\StorageLocation\StorageLocation $storageLocation The storage location + */ + public function getStorageLocation () { + return $this->storageLocation; + } + + /** + * Sets the footprint for this part + * @param \PartKeepr\Footprint\Footprint $footprint The footprint to set + */ + public function setFootprint (Footprint $footprint = null) { + $this->footprint = $footprint; + } + + /** + * Sets the comment for this part + * @param string $comment The comment for this part + */ + public function setComment ($comment) { + $this->comment = $comment; + } + + /** + * Returns the comment for this part + * @return string The comment + */ + public function getComment () { + return $this->comment; + } + + /** + * Returns the distributors array + * @return ArrayCollection the distributors + */ + public function getDistributors () { + return $this->distributors; + } + + /** + * Returns the part images array + * @return ArrayCollection the part images + */ + public function getImages () { + return $this->images; + } + + /** + * Returns the part attachments array + * @return ArrayCollection the part attachments + */ + public function getAttachments () { + return $this->attachments; + } + + /** + * Returns the manufacturers array + * @return ArrayCollection the manufactuers + */ + public function getManufacturers () { + return $this->manufacturers; + } + + /** + * Returns the parameters assigned to this part + * @return array An array of PartParameter objects + */ + public function getParameters () { + return $this->parameters; + } + + /** + * Returns the stock level of this part. This is a realtime function which + * actually creates a query over the StockEntry table. + * @return int The stock level + */ + public function getStockLevel () { + $query = PartKeepr::getEM()->createQuery("SELECT SUM(s.stockLevel) FROM PartKeepr\Stock\StockEntry s WHERE s.part = :part"); + $query->setParameter("part", $this); + + return $query->getSingleScalarResult(); + } + + /** + * Sets the create date for this part + * @param \DateTime $dateTime The create date+time + */ + private function setCreateDate (\DateTime $dateTime) { + $this->createDate = $dateTime; + } + + /** + * Returns the create date + * @return \DateTime The create date+time + */ + public function getCreateDate () { + return $this->createDate; + } + + /** + * Sets the status for this part. A status is any string describing the status, + * e.g. "new", "used", "broken" etc. + * @param string $status The status + */ + public function setStatus ($status) { + $this->status = $status; + } + + /** + * Returns the status for this part. + * @return string The status + */ + public function getStatus () { + return $this->status; + } + + public function updateCacheData () { + $this->updateStockLevel(); + $this->updatePrice(); + } + + /** + * Updates the average price for a part + */ + public function updatePrice () { + $query = PartKeepr::getEM()->createQuery("SELECT SUM(se.price*se.stockLevel) / SUM(se.stockLevel) FROM PartKeepr\Stock\StockEntry se WHERE se.part = :part AND se.stockLevel > 0"); + $query->setParameter("part", $this); + $val = $query->getSingleScalarResult(); + + $query = PartKeepr::getEM()->createQuery('UPDATE PartKeepr\Part\Part p SET p.averagePrice = :val WHERE p = :part'); + $query->setParameter("val", $val); + $query->setParameter("part", $this); + $query->execute(); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "description" => $this->getDescription(), + "comment" => $this->getComment(), + "stockLevel" => $this->getStockLevel(), + "footprint" => is_object($this->footprint) ? $this->footprint->getId() : null, + "minStockLevel" => $this->minStockLevel, + "status" => $this->getStatus(), + "storageLocation" => is_object($this->storageLocation) ? $this->storageLocation->getId() : null, + "category" => is_object($this->category) ? $this->category->getId() : null, + "partUnit" => is_object($this->partUnit) ? $this->getPartUnit()->getId() : null, + "manufacturers" => $this->serializeChildren($this->getManufacturers()), + "distributors" => $this->serializeChildren($this->getDistributors()), + "images" => $this->serializeChildren($this->getImages()), + "attachments" => $this->serializeChildren($this->getAttachments()), + "parameters" => $this->serializeChildren($this->getParameters()), + "createDate" => $this->getCreateDate()->format("Y-m-d H:i:s"), + "needsReview" => $this->getReviewFlag(), + "internalPartNumber" => $this->getInternalPartNumber(), + // Additional things we serialize to make displaying stuff in the frontend easier + "categoryName" => is_object($this->category) ? $this->category->getName() : null, + "footprintName" => is_object($this->footprint) ? $this->footprint->getName() : null, + "storageLocationName" => is_object($this->storageLocation) ? $this->storageLocation->getName() : null + ); + } + + /** + * Deserializes the part + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "description": + $this->setDescription($value); + break; + case "comment": + $this->setComment($value); + break; + case "internalPartNumber": + $this->setInternalPartNumber($value); + break; + case "footprint": + if ($value === 0) { + $this->setFootprint(null); + } else { + try { + $footprint = Footprint::loadById($value); + $this->setFootprint($footprint); + } catch (\Exception $e) { + // No footprint was found. Ignore it. + } + } + break; + case "minStockLevel": + $this->setMinStockLevel($value); + break; + case "partUnit": + $partUnit = PartUnit::loadById($value); + $this->setPartUnit($partUnit); + break; + case "category": + $category = PartCategory::loadById($value); + $this->setCategory($category); + break; + case "status": + $this->setStatus($value); + break; + case "storageLocation": + $storageLocation = StorageLocation::loadById($value); + $this->setStorageLocation($storageLocation); + break; + case "manufacturers": + $this->deserializeChildren($value, $this->getManufacturers(), "PartKeepr\Part\PartManufacturer"); + foreach ($this->getManufacturers() as $manufacturer) { + $manufacturer->setPart($this); + } + break; + case "distributors": + $this->deserializeChildren($value, $this->getDistributors(), "PartKeepr\Part\PartDistributor"); + foreach ($this->getDistributors() as $distributor) { + $distributor->setPart($this); + } + break; + case "parameters": + $this->deserializeChildren($value, $this->getParameters(), "PartKeepr\PartParameter\PartParameter"); + foreach ($this->getParameters() as $parameter) { + $parameter->setPart($this); + } + break; + case "needsReview": + $this->setReviewFlag($value); + break; + case "attachments": + $this->deserializeChildren($value, $this->getAttachments(), "PartKeepr\Part\PartAttachment"); + foreach ($this->getAttachments() as $attachment) { + $attachment->setPart($this); + } + break; + } + } + } + + /** + * Checks if the part category is set. + * + * @throws CategoryNotAssignedException + */ + private function checkCategoryConsistency () { + if ($this->getCategory() === null) { + throw new CategoryNotAssignedException($this); + } + } + + /** + * Checks if the part storage location is set. + * + * @throws StorageLocationNotAssignedException + */ + private function checkStorageLocationConsistency () { + if ($this->getStorageLocation() === null) { + throw new StorageLocationNotAssignedException(); + } + } + + /** + * Checks if the requirements for database persisting are given. + * + * @throws CategoryNotAssignedException Thrown if no category is set + * @throws StorageLocationNotAssignedException Thrown if no storage location is set + * + * @PrePersist + */ + public function onPrePersist () { + $this->checkCategoryConsistency(); + $this->checkStorageLocationConsistency(); + } + + /** + * + * Checks if the requirements for database persisting are given. + * + * For a list of exceptions, see + * @see PartKeepr\Part.Part::onPrePersist() + * + * @PreUpdate */ + public function onPreUpdate () { + $this->checkCategoryConsistency(); + $this->checkStorageLocationConsistency(); + } + + /** + * Returns a string representation of the part + * + * @param none + * @return string The name and the ID of the part + */ + public function __toString () { + return $this->getName() . " (".$this->getId().")"; + } + +} diff --git a/src/backend/PartKeepr/Part/PartAttachment.php b/src/backend/PartKeepr/Part/PartAttachment.php @@ -0,0 +1,129 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\UploadedFile\UploadedFile; + +/** + * Holds a part attachment + * @Entity + **/ +class PartAttachment extends UploadedFile implements Serializable, Deserializable { + /** + * The description of this attachment + * @Column(type="text") + * @var string + */ + private $description; + + /** + * Creates a new part attachment + */ + public function __construct () { + parent::__construct(); + $this->setType("PartAttachment"); + } + + /** + * The part object + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + * @var Part + */ + private $part = null; + + /** + * Sets the part + * @param Part $part The part to set + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part + * @return Part the part + */ + public function getPart () { + return $this->part; + } + + /** + * Sets the description for this attachment + * @param string $description The attachment description + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description for this attachment + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * + * Serializes this part attachment + * @return array The serialized part attachment + */ + public function serialize () { + return array( + "id" => $this->getId(), + "part_id" => $this->getPart()->getId(), + "originalFilename" => $this->getOriginalFilename(), + "mimetype" => $this->getMimetype(), + "extension" => $this->getExtension(), + "size" => $this->getSize(), + "description" => $this->getDescription(), + "image" => $this->isImage()); + } + + /** + * Deserializes the part attachment + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + if (array_key_exists("id", $parameters)) { + if (substr($parameters["id"], 0, 4) === "TMP:") { + $this->replaceFromTemporaryFile($parameters["id"]); + } + } + + foreach ($parameters as $key => $value) { + switch ($key) { + case "description": + $this->setDescription($value); + break; + } + } + } + + /** + * Returns if the attachment is an image or not. + * + * Ths method uses ImageMagick to find out if this is an image. Limitations apply; if ImageMagick doesn't support + * the image format, this method would return false, even if it is an image. + * + * @return True if the attachment is an image, false otherwise + */ + public function isImage () { + /** + * Special case: Check if it's a PDF. If yes, return immediately. + * This is because ImageMagick outputs warning messages for malformed PDF files, and halts the execution + * of the script for several seconds. DO NOT REMOVE! + */ + if ($this->getMimeType() == "application/pdf") { + return false; + } + + try { + $im = new \Imagick($this->getFilename()); + return true; + } catch (\ImagickException $e) { + return false; + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/PartDistributor.php b/src/backend/PartKeepr/Part/PartDistributor.php @@ -0,0 +1,220 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr, + PartKeepr\Distributor\Distributor; + +/** + * This class represents the link between a part and a distributor. + * @Entity **/ +class PartDistributor extends BaseEntity implements Serializable, Deserializable { + /** + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + */ + private $part; + + /** + * @ManyToOne(targetEntity="PartKeepr\Distributor\Distributor") + */ + private $distributor; + + /** + * The order number for the part and distributor + * @Column(type="string",nullable=true) + * @var string + */ + private $orderNumber; + + /** + * Defines the packaging unit when ordering a part. Some items can't be ordered in a quantity of just one at + * certain manufacturers. + * + * @Column(type="integer") + * @var integer + */ + private $packagingUnit; + + /** + * Specifies the price of the part. Note that the price + * needs to be per item, not per packaging unit. + * + * @Column(type="decimal",precision=13,scale=4,nullable=true) + * @var float + */ + private $price; + + /** + * The distributor's SKU (stock keeping unit) for the part. Used with barcodes. + * @Column(type="string",nullable=true) + * @var string + */ + private $sku; + + /** + * Cretes a new part->distributor link. Initializes the packaging unit with a quantity of "1". + * + * @param Part $part The part + * @param Distributor $distributor The distributor + */ + public function __construct () { + $this->setPackagingUnit(1); + } + + /** + * Sets the packaging unit for a specific distributor. + * + * For example, some distributors only sell resistors in packs of 100, so you can't order just one. We use the + * packagingUnit to calculate how many pieces will be delivered once ordered. So if your stock level falls below + * the minimum (example: you would need to order 10 resistors), we suggest that you only order one resistor pack + * instead of 10. + * + * @param int $packagingUnit The amount of items in one package + * @throws \PartKeepr\Part\OutOfRangeException When the packaging unit is less than 1 + */ + public function setPackagingUnit ($packagingUnit) { + $packagingUnit = intval($packagingUnit); + + if ($packagingUnit < 1) { + $exception = new OutOfRangeException(PartKeepr::i18n("Packaging Unit is out of range")); + $exception->setDetail(PartKeepr::i18n("The packaging unit must be 1 or higher")); + throw $exception; + } + + $this->packagingUnit = $packagingUnit; + } + + /** + * Returns the packaging unit + * @return int The packaging unit + */ + public function getPackagingUnit () { + return $this->packagingUnit; + } + + /** + * Sets the part + * @param Part $part The part + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part + * @return Part The part + */ + public function getPart () { + return $this->part; + } + + /** + * Sets the distributor + * @param Distributor $distributor The distributor + */ + public function setDistributor (Distributor $distributor) { + $this->distributor = $distributor; + } + + /** + * Returns the distributor + * @return Distributor The distributor + */ + public function getDistributor () { + return $this->distributor; + } + + /** + * Sets the order number + * @param string $orderNumber The order number + */ + public function setOrderNumber ($orderNumber) { + $this->orderNumber = $orderNumber; + } + + /** + * Returns the order number + * @return string The order number + */ + public function getOrderNumber () { + return $this->orderNumber; + } + + /** + * Sets the price + * @param float $price + */ + public function setPrice ($price) { + echo "/** price set to ".$price." **/"; + $this->price = $price; + } + + /** + * Returns the price + */ + public function getPrice () { + return $this->price; + } + + /** + * Sets the SKU (stock keeping unit) + * @param string $sku The SKU + */ + public function setSKU ($sku) { + $this->sku = $sku; + } + + /** + * Returns the SKU (stock keeping unit) + * @return string The SKU + */ + public function getSKU () { + return $this->sku; + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "id" => $this->getId(), + "orderNumber" => $this->getOrderNumber(), + "distributor_id" => $this->getDistributor()->getId(), + "distributor_name" => $this->getDistributor()->getName(), + "part_id" => $this->getPart()->getId(), + "part_name" => $this->getPart()->getName(), + "packagingUnit" => $this->getPackagingUnit(), + "price" => $this->getPrice(), + "sku" => $this->getSKU()); + } + + /** + * Deserializes the part manufacturer + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "distributor_id": + $distributor = Distributor::loadById($value); + $this->setDistributor($distributor); + break; + case "orderNumber": + $this->setOrderNumber($value); + break; + case "packagingUnit": + $this->setPackagingUnit($value); + break; + case "price": + $this->setPrice($value); + break; + case "sku": + $this->setSKU($value); + break; + } + } + } +} diff --git a/src/backend/PartKeepr/Part/PartFulltextSearch.php b/src/backend/PartKeepr/Part/PartFulltextSearch.php @@ -0,0 +1,29 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\FulltextSearch\FulltextSearch; + +/** + * Implements the part fulltext search + */ +class PartFulltextSearch extends FulltextSearch { + /** + * Returns the FQDN of the part entity + * + * (non-PHPdoc) + * @see PartKeepr\FulltextSearch.FulltextSearch::getEntityName() + */ + protected function getEntityName () { + return 'PartKeepr\Part\Part'; + } + + /** + * Returns the fields to be searched in + * + * (non-PHPdoc) + * @see PartKeepr\FulltextSearch.FulltextSearch::getFields() + */ + protected function getFields () { + return array("comment", "name", "description", "internalPartNumber"); + } +} diff --git a/src/backend/PartKeepr/Part/PartImage.php b/src/backend/PartKeepr/Part/PartImage.php @@ -0,0 +1,50 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\Util\Serializable, + PartKeepr\Image\Image; + +/** + * Holds a part image + * @Entity + **/ +class PartImage extends Image implements Serializable { + /** + * The part object + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + * @var Part + */ + private $part = null; + + /** + * Creates a new part image instance + */ + public function __construct () { + parent::__construct(Image::IMAGE_PART); + } + + /** + * Sets the part + * @param Part $part The part to set + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part + * @return Part the part + */ + public function getPart () { + return $this->part; + } + + /** + * + * Serializes this part image + * @return array The serialized part imaage + */ + public function serialize () { + return array("id" => $this->getId(), "part_id" => $this->getPart()->getId()); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/PartManager.php b/src/backend/PartKeepr/Part/PartManager.php @@ -0,0 +1,441 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\Logger\Logger; + +use PartKeepr\UploadedFile\TempUploadedFile, + PartKeepr\Manager\ManagerFilter, + Doctrine\ORM\QueryBuilder, + PartKeepr\PartParameter\PartParameter, + PartKeepr\Manager\AbstractManager, + PartKeepr\Unit\Unit, + PartKeepr\SiPrefix\SiPrefix, + PartKeepr\Part\PartDistributor, + PartKeepr\Part\PartManufacturer, + PartKeepr\StorageLocation\StorageLocation, + PartKeepr\StorageLocation\StorageLocationManager, + PartKeepr\Part\Part, + Doctrine\ORM\Query, + PartKeepr\PartUnit\PartUnitManager, + PartKeepr\Distributor\Distributor, + PartKeepr\Manufacturer\Manufacturer, + PartKeepr\Footprint\FootprintManager, + PartKeepr\Session\SessionManager, + PartKeepr\Stock\StockEntry, + PartKeepr\Util\Singleton, + PartKeepr\Footprint\Footprint, + PartKeepr\PartKeepr, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Manufacturer\ManufacturerManager; + +class PartManager 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\Part\Part'; + } + + /** + * 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("name", "description", "averagePrice", "status", "needsReview", "createDate", "id", "stockLevel", + "minStockLevel", "comment", "st.id AS storageLocation_id", "c.categoryPath AS categoryPath", + "st.name as storageLocationName", "f.id AS footprint_id", "f.name AS footprintName", + "c.id AS category", "c.name AS categoryName", "pu.id AS partUnit", "pu.name AS partUnitName", + "pu.is_default AS partUnitDefault" + ); + } + + /** + * Returns the default sort field + * + * @return string The default sort field + */ + public function getDefaultSortField () { + return "dateTime"; + } + + /** + * Appends various join tables to the result set + * + * (non-PHPdoc) + * @see PartKeepr\Manager.AbstractManager::applyCustomQuery() + */ + protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { + /** + * Pull in additional tables + */ + $qb ->join("q.storageLocation", "st") + ->leftJoin("q.footprint", "f") + ->join("q.category", "c") + ->leftJoin("q.partUnit", "pu"); + + // Apply special handling for non-direct fields in relations, where the frontend has no idea about. + foreach ($filter->getSorters() as $sorter) { + switch ($sorter->getSortField()) { + case "q.categoryPath": + $sorter->setSortField("c.categoryPath"); + break; + case "q.storageLocationName": + $sorter->setSortField("st.name"); + break; + case "q.footprintName": + $sorter->setSortField("f.name"); + break; + default: + break; + } + } + + } + + /** + * Processes the result after it was retrieved. In the default configuration, it returns an array result, or + * if no query fields are specified, it tries to serialize all objects. + */ + protected function getResult (Query $query) { + $result = parent::getResult($query); + + /* Add attachment counts to the result set and re-format the date */ + foreach ($result as $key => $item) { + $dql = "SELECT COUNT(pa) FROM PartKeepr\Part\PartAttachment pa WHERE pa.part = :part"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("part", $item["id"]); + + $result[$key]["attachmentCount"] = $query->getSingleScalarResult(); + + $result[$key]["createDate"] = $result[$key]["createDate"]->format("Y-m-d H:i:s"); + } + + foreach ($result as $key => $item) { + $dql = "SELECT pr.name FROM PartKeepr\Project\Project pr JOIN pr.parts ppart WHERE ppart.part = :part"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("part", $item["id"]); + + $projectNames = array(); + foreach ($query->getArrayResult() as $project) { + $projectNames[] = $project["name"]; + } + + $result[$key]["projects"] = implode(", ", $projectNames); + + } + + foreach ($result as $key => $item) { + $part = Part::loadById($item["id"]); + $result[$key]["attachments"] = $part->serializeChildren($part->getAttachments()); + } + + return $result; + } + + public function addOrUpdatePart ($aParameters) { + + if (!array_key_exists("quantity", $aParameters)) { + $aParameters["quantity"] = 0; + } + + if ($aParameters["part"] !== null) { + try { + $part = $this->getPart($aParameters["part"]); + } catch (\Exception $e) { + $part = new Part(); + $user = SessionManager::getCurrentSession()->getUser(); + + $stock = new StockEntry($part, $aParameters["quantity"], $user); + PartKeepr::getEM()->persist($stock); + } + } else { + $part = new Part(); + + $user = SessionManager::getCurrentSession()->getUser(); + + $stock = new StockEntry($part, $aParameters["quantity"], $user); + PartKeepr::getEM()->persist($stock); + } + + if (array_key_exists("name", $aParameters)) { + $part->setName($aParameters["name"]); + } + + if (array_key_exists("description", $aParameters)) { + $part->setDescription($aParameters["description"]); + } + + if (array_key_exists("minstock", $aParameters)) { + $part->setMinStockLevel($aParameters["minstock"]); + } + + if (array_key_exists("comment", $aParameters)) { + $part->setComment($aParameters["comment"]); + } + + if (array_key_exists("footprint", $aParameters)) { + + if ($aParameters["footprint"] === null) { + $part->setFootprint(null); + } else { + $footprint = FootprintManager::getInstance()->getOrCreateFootprint($aParameters["footprint"]); + $part->setFootprint($footprint); + } + } + + if (array_key_exists("storagelocation", $aParameters)) { + $storageLocation = StorageLocationManager::getInstance()->getOrCreateStorageLocation($aParameters["storagelocation"]); + $part->setStorageLocation($storageLocation); + } + + if (array_key_exists("category", $aParameters)) { + $category = PartCategoryManager::getInstance()->getCategory($aParameters["category"]); + $part->setCategory($category->getNode()); + } + + /* Process linked changes */ + if (array_key_exists("distributorChanges", $aParameters)) { + if (is_array($aParameters["distributorChanges"])) { + $this->processDistributorChanges($part, $aParameters["distributorChanges"]); + } + } + + if (array_key_exists("manufacturerChanges", $aParameters)) { + if (is_array($aParameters["manufacturerChanges"])) { + $this->processManufacturerChanges($part, $aParameters["manufacturerChanges"]); + } + } + + if (array_key_exists("parameterChanges", $aParameters)) { + if (is_array($aParameters["parameterChanges"])) { + $this->processParameterChanges($part, $aParameters["parameterChanges"]); + } + } + + if (array_key_exists("attachmentChanges", $aParameters)) { + if (is_array($aParameters["attachmentChanges"])) { + $this->processAttachmentChanges($part, $aParameters["attachmentChanges"]); + } + } + + if (array_key_exists("partUnit", $aParameters)) { + if ($aParameters["partUnit"] === null || $aParameters["partUnit"] === 0) { + $part->setPartUnit(null); + } else { + $part->setPartUnit(PartUnitManager::getInstance()->getPartUnit($aParameters["partUnit"])); + } + } + + + PartKeepr::getEM()->persist($part); + PartKeepr::getEM()->flush(); + + } + + private function processParameterChanges (Part $part, Array $data) { + if (array_key_exists("updates", $data)) { + foreach ($data["updates"] as $record) { + foreach ($part->getParameters() as $partParameter) { + if ($partParameter->getId() == $record["id"]) { + $partParameter->setName($record["name"]); + $partParameter->setDescription($record["description"]); + $partParameter->setValue($record["value"]); + $partParameter->setSiPrefix(SiPrefix::loadById($record["siprefix_id"])); + $partParameter->setUnit(Unit::loadById($record["unit_id"])); + break; + } + } + } + } + + if (array_key_exists("removals", $data)) { + foreach ($data["removals"] as $record) { + foreach ($part->getParameters() as $partParameter) { + if ($partParameter->getId() == $record["id"]) { + PartKeepr::getEM()->remove($partParameter); + $part->getParameters()->removeElement($partParameter); + break; + } + } + } + } + + if (array_key_exists("inserts", $data)) { + foreach ($data["inserts"] as $record) { + $partParameter = new PartParameter(); + $partParameter->setPart($part); + + $partParameter->setName($record["name"]); + $partParameter->setDescription($record["description"]); + $partParameter->setValue($record["value"]); + $partParameter->setSiPrefix(SiPrefix::loadById($record["siprefix_id"])); + $partParameter->setUnit(Unit::loadById($record["unit_id"])); + + $part->getParameters()->add($partParameter); + } + } + } + + private function processDistributorChanges (Part $part, Array $data) { + if (array_key_exists("updates", $data)) { + foreach ($data["updates"] as $record) { + foreach ($part->getDistributors() as $partDistributor) { + if ($partDistributor->getId() == $record["id"]) { + $partDistributor->setOrderNumber($record["orderNumber"]); + $partDistributor->setDistributor(Distributor::loadById($record["distributor_id"])); + $partDistributor->setPackagingUnit($record["packagingUnit"]); + break; + } + } + } + } + + if (array_key_exists("removals", $data)) { + foreach ($data["removals"] as $record) { + foreach ($part->getDistributors() as $partDistributor) { + if ($partDistributor->getId() == $record["id"]) { + PartKeepr::getEM()->remove($partDistributor); + $part->getDistributors()->removeElement($partDistributor); + break; + } + } + } + } + + if (array_key_exists("inserts", $data)) { + foreach ($data["inserts"] as $record) { + $distributor = new PartDistributor($part, Distributor::loadById($record["distributor_id"])); + $distributor->setOrderNumber($record["orderNumber"]); + $distributor->setPackagingUnit($record["packagingUnit"]); + + $part->getDistributors()->add($distributor); + } + } + } + + private function processManufacturerChanges (Part $part, Array $data) { + if (array_key_exists("updates", $data)) { + foreach ($data["updates"] as $record) { + foreach ($part->getManufacturers() as $partManufacturer) { + if ($partManufacturer->getId() == $record["id"]) { + $partManufacturer->setPartNumber($record["partNumber"]); + $partManufacturer->setManufacturer(Manufacturer::loadById($record["manufacturer_id"])); + break; + } + } + } + } + + if (array_key_exists("removals", $data)) { + foreach ($data["removals"] as $record) { + foreach ($part->getManufacturers() as $partManufacturer) { + if ($partManufacturer->getId() == $record["id"]) { + PartKeepr::getEM()->remove($partManufacturer); + $part->getManufacturers()->removeElement($partManufacturer); + break; + } + } + } + } + + if (array_key_exists("inserts", $data)) { + foreach ($data["inserts"] as $record) { + $manufacturer = new PartManufacturer($part, Manufacturer::loadById($record["manufacturer_id"])); + $manufacturer->setPartNumber($record["partNumber"]); + + $part->getManufacturers()->add($manufacturer); + } + } + } + + private function processAttachmentChanges (Part $part, Array $data) { + if (array_key_exists("updates", $data)) { + foreach ($data["updates"] as $record) { + foreach ($part->getAttachments() as $partAttachment) { + if ($partAttachment->getId() == $record["id"]) { + $partAttachment->setDescription($record["description"]); + break; + } + } + } + } + + if (array_key_exists("removals", $data)) { + foreach ($data["removals"] as $record) { + foreach ($part->getAttachments() as $partAttachment) { + if ($partAttachment->getId() == $record["id"]) { + PartKeepr::getEM()->remove($partAttachment); + $part->getAttachments()->removeElement($partAttachment); + break; + } + } + } + } + + if (array_key_exists("inserts", $data)) { + foreach ($data["inserts"] as $record) { + $attachment = new PartAttachment(); + $attachment->setPart($part); + $attachment->setDescription($record["description"]); + + $file = TempUploadedFile::loadById($record["tmp_id"]); + + $attachment->replace($file->getFilename()); + $attachment->setOriginalFilename($file->getOriginalFilename()); + + $part->getAttachments()->add($attachment); + } + } + } + + public function deletePart ($id) { + $part = PartManager::getInstance()->getPart($id); + + PartKeepr::getEM()->remove($part); + PartKeepr::getEM()->flush(); + } + + public function getPart ($id) { + $part = PartKeepr::getEM()->find("PartKeepr\Part\Part", $id); + + return $part; + } + + /** + * Returns the overall part count currently existing. + * @param boolean $withPrice Only consider parts with a price + * @return int The amount of parts in the database + */ + public function getPartCount ($withPrice = false) { + $dql = "SELECT COUNT(p.id) FROM PartKeepr\Part\Part p"; + + if ($withPrice === true) { + $dql .= " WHERE p.averagePrice IS NOT NULL"; + } + + return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); + } + + /** + * Returns the total price for all parts. Only parts with a price are calculated. + * @return float The total price + */ + public function getTotalPrice () { + $dql = "SELECT SUM(p.averagePrice * p.stockLevel) FROM PartKeepr\Part\Part p"; + + return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); + } + + /** + * Returns the average price for all parts. Only parts with a price are calculated. + * @return float The average price + */ + public function getAveragePrice () { + $dql = "SELECT AVG(p.averagePrice) FROM PartKeepr\Part\Part p"; + + return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/PartManufacturer.php b/src/backend/PartKeepr/Part/PartManufacturer.php @@ -0,0 +1,106 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr, + PartKeepr\Manufacturer\Manufacturer; + +/** @Entity **/ +class PartManufacturer extends BaseEntity implements Serializable, Deserializable { + /** + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + */ + private $part; + + /** + * @ManyToOne(targetEntity="PartKeepr\Manufacturer\Manufacturer") + */ + private $manufacturer; + + /** + * @Column(type="string",nullable=true) + * Enter description here ... + * @var unknown_type + */ + private $partNumber; + + /** + * Sets the part which belongs to this manufacturer entry + * @param Part $part + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part which belongs to this manufacturer entry + */ + public function getPart () { + return $this->part; + } + + /** + * Sets the manufacturer which belongs to this entry + * @param Manufacturer $manufacturer + */ + public function setManufacturer (Manufacturer $manufacturer) { + $this->manufacturer = $manufacturer; + } + + /** + * Returns the manufacturer which belongs to this part + */ + public function getManufacturer () { + return $this->manufacturer; + } + + /** + * Sets the manufacturer-specific part number + * @param string $partNumber + */ + public function setPartNumber ($partNumber) { + $this->partNumber = $partNumber; + } + + /** + * Returns the manufacturer-specific part number + * @return string The part number + */ + public function getPartNumber () { + return $this->partNumber; + } + + /** + * Returns the data of this object in a serialized form. + * @return array The result array + */ + public function serialize () { + return array( + "id" => $this->getId(), + "partNumber" => $this->getPartNumber(), + "manufacturer_id" => $this->getManufacturer()->getId(), + "manufacturer_name" => $this->getManufacturer()->getName(), + "part_id" => $this->getPart()->getId(), + "part_name" => $this->getPart()->getName()); + } + + /** + * Deserializes the part manufacturer + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "manufacturer_id": + $manufacturer = Manufacturer::loadById($value); + $this->setManufacturer($manufacturer); + break; + case "partNumber": + $this->setPartNumber($value); + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/PartService.php b/src/backend/PartKeepr/Part/PartService.php @@ -0,0 +1,262 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\User\User, + PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\Manager\ManagerFilter, + PartKeepr\Part\PartManager, + PartKeepr\Stock\StockEntry, + PartKeepr\PartKeepr, + PartKeepr\PartCategory\PartCategory, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Session\SessionManager; + +class PartService extends Service implements RestfulService { + public function get () { + if ($this->hasParameter("id")) { + return array("data" => PartManager::getInstance()->getPart($this->getParameter("id"))->serialize()); + } else { + + $filter = new ManagerFilter($this); + $filter->setFilterCallback(array($this, "filterCallback")); + + return PartManager::getInstance()->getList($filter); + } + } + + /** + * Advanced filtering for the list + * @param QueryBuilder The $queryBuilder + */ + public function filterCallback ($queryBuilder) { + + /** + * Applies text-based filtering + */ + if ($this->hasParameter("query") && $this->getParameter("query") != "") { + + $fulltextSearch = new PartFulltextSearch($this->getParameter("query")); + $fulltextSearchResults = $fulltextSearch->query(); + + $queryBuilder->andWhere("q.id IN (".implode(",", $fulltextSearchResults).")"); + + } + + /** + * Applies filtering by the storage location name + */ + if ($this->getParameter("storageLocation") !== null) { + $queryBuilder->andWhere("st.name = :storageLocation"); + $queryBuilder->setParameter("storageLocation", $this->getParameter("storageLocation")); + } + + /** + * Filter by the category id and set the category mode + * + */ + $category = intval($this->getParameter("category", 0)); + + if ($category !== 0) { + /* Fetch all children */ + if ($this->getParameter("categoryScope") == "selected") { + $queryBuilder->andWhere("q.category = :category"); + $queryBuilder->setParameter("category", $category); + } else { + $childs = PartCategoryManager::getInstance()->getChildNodes($category); + $childs[] = $category; + $queryBuilder->andWhere("q.category IN (".implode(",", $childs).")"); + } + } + + /** + * Filter by the stock mode + */ + switch ($this->getParameter("stockMode")) { + case "all": + break; + case "zero": + $queryBuilder->andWhere("q.stockLevel = 0"); + break; + case "nonzero": + $queryBuilder->andWhere("q.stockLevel > 0"); + break; + case "below": + $queryBuilder->andWhere("q.stockLevel < q.minStockLevel"); + break; + } + + /** + * Query by the distributor's order number + */ + if ($this->getParameter("distributorOrderNumber")) { + $queryBuilder->leftJoin("q.distributors", "di"); + $queryBuilder->andWhere("LOWER(di.orderNumber) LIKE :orderNumber"); + $queryBuilder->setParameter("orderNumber", "%".strtolower($this->getParameter("distributorOrderNumber"))."%"); + } + + /** + * Filter by the price + */ + if ($this->getParameter("withoutPrice") === true || $this->getParameter("withoutPrice") === "true") { + $queryBuilder->andWhere("q.averagePrice IS NULL"); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $entity = PartManager::getInstance()->createEntity($this->getParameters()); + + if ($this->getParameter("initialStockLevel") > 0) { + try { + $user = User::loadById($this->getParameter("initialStockLevelUser")); + } catch (\Exception $e) { + $user = SessionManager::getCurrentSession()->getUser(); + } + + $stock = new StockEntry($entity, intval($this->getParameter("initialStockLevel")), $user); + + if ($this->getParameter("initialStockLevelPricePerItem") == true) { + $price = floatval($this->getParameter("initialStockLevelPrice")); + } else { + $price = floatval($this->getParameter("initialStockLevelPrice")) / $this->getParameter("initialStockLevel"); + } + + if ($price != 0) { + $stock->setPrice($price); + } + + PartKeepr::getEM()->persist($stock); + PartKeepr::getEM()->flush(); + + $entity->updateStockLevel(); + PartKeepr::getEM()->flush(); + } + + return array("data" => $entity->serialize()); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + $entity = PartManager::getInstance()->getEntity($this->getParameter("id")); + $entity->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $entity->serialize()); + } + + + public function destroy () { + throw new \Exception("Not yet implemented"); + } + + public function getPartParameterNames () { + $dql = "SELECT pp.name FROM PartKeepr\PartParameter\PartParameter pp GROUP BY pp.name"; + $query = PartKeepr::getEM()->createQuery($dql); + + return array("data" => $query->getArrayResult()); + } + + public function movePart () { + $this->requireParameter("targetCategory"); + + if ($this->getParameter("parts", false) !== false) { + /* We are moving multiple parts */ + foreach ($this->getParameter("parts") as $part) { + $part = Part::loadById($part); + $category = PartCategory::loadById($this->getParameter("targetCategory")); + + $part->setCategory($category); + } + } else { + $part = Part::loadById($this->getParameter("part")); + $category = PartCategory::loadById($this->getParameter("targetCategory")); + + $part->setCategory($category); + + } + + PartKeepr::getEM()->flush(); + } + + public function addStock () { + $part = PartManager::getInstance()->getPart($this->getParameter("part")); + + $user = SessionManager::getCurrentSession()->getUser(); + + $stock = new StockEntry($part, intval($this->getParameter("stock")), $user); + + $price = floatval($this->getParameter("price")); + + if ($price != 0) { + $stock->setPrice($price); + } + + if ($this->hasParameter("comment")) { + $stock->setComment($this->getParameter("comment")); + } + + PartKeepr::getEM()->persist($stock); + PartKeepr::getEM()->flush(); + + $part->updateStockLevel(); + + PartKeepr::getEM()->flush(); + + return array("data" => $part->serialize()); + } + + public function deleteStock () { + $part = PartManager::getInstance()->getPart($this->getParameter("part")); + + $user = SessionManager::getCurrentSession()->getUser(); + + $stock = new StockEntry($part, 0-intval($this->getParameter("stock")), $user); + + PartKeepr::getEM()->persist($stock); + PartKeepr::getEM()->flush(); + + $part->updateStockLevel(); + + PartKeepr::getEM()->flush(); + + return array("data" => $part->serialize()); + } + + public function massDeleteStock () { + $data = $this->getParameter("removals"); + + $updateStockLevels = array(); + + foreach ($data as $item) { + $part = PartManager::getInstance()->getPart($item["part"]); + $user = SessionManager::getCurrentSession()->getUser(); + + $stock = new StockEntry($part, 0-intval($item["amount"]), $user); + $stock->setComment($item["comment"]); + PartKeepr::getEM()->persist($stock); + + $updateStockLevels[$item["part"]] = $part; + } + + PartKeepr::getEM()->flush(); + + foreach ($updateStockLevels as $part) { + $part->updateStockLevel(); + } + + PartKeepr::getEM()->flush(); + return array(); + } + + public function deletePart () { + PartManager::getInstance()->deletePart($this->getParameter("part")); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Part/PartUnit.php b/src/backend/PartKeepr/Part/PartUnit.php @@ -0,0 +1,137 @@ +<?php +namespace PartKeepr\Part; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr, + PartKeepr\Util\Exceptions\OutOfRangeException; + + +/** @Entity **/ +class PartUnit extends BaseEntity implements Serializable, Deserializable { + /** + * Defines the name of the unit + * @Column + * @var string + */ + private $name; + + /** + * Defines the short name of the unit + * @Column + * @var string + */ + private $shortName; + + /** + * Defines if the unit is default or not. + * + * @Column(type="boolean") + * @var boolean + */ + private $is_default; + + /** + * @OneToMany(targetEntity="PartKeepr\Part\Part",mappedBy="partUnit") + */ + private $parts; + + + /** + * Creates a new part unit. + * + * Sets the default to false. + */ + public function __construct () { + $this->setDefault(false); + } + + /** + * Sets the name for this unit + * @param string $name The name for this unit + * @return nothing + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name for this unit + * @param none + * @return string The name for this unit + */ + public function getName () { + return $this->name; + } + + /** + * Sets the short name for this unit. + * + * Short names are used for list views (e.g. if your unit name is "metres", your short name could be "m") + * @param string $shortName The short name + * @return nothing + */ + public function setShortName ($shortName) { + $this->shortName = $shortName; + } + + /** + * Returns the short name for this unit + * @param none + * @return string The short name for this unit + */ + public function getShortName () { + return $this->shortName; + } + + /** + * Defines if the unit is default or not. + * @param boolean $default True if the unit is default, false otherwise + */ + public function setDefault ($default) { + $this->is_default = (bool)$default; + } + + /** + * Returns if the unit is default or not + * @param none + * @return boolean True if the unit is default, false for not + */ + public function getDefault () { + return $this->is_default; + } + + /** + * Serializes the object and returns it as array, suitable + * to process via json_encode. + * @param none + * @return array An array containing the object information + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "shortName" => $this->getShortName(), + "default" => $this->getDefault() + ); + } + + /** + * Deserializes the manufacturer + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "shortName": + $this->setShortName($value); + break; + } + } + } +} + + \ No newline at end of file diff --git a/src/backend/PartKeepr/PartCategory/PartCategory.php b/src/backend/PartKeepr/PartCategory/PartCategory.php @@ -0,0 +1,14 @@ +<?php +namespace PartKeepr\PartCategory; + +use PartKeepr\Category\AbstractCategory; + +/** + * @Entity + * @Table(indexes={@index(columns={"lft"}),@index(columns={"rgt"})}) + * The entity for our part categories + * + */ +class PartCategory extends AbstractCategory { + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/PartCategory/PartCategoryManager.php b/src/backend/PartKeepr/PartCategory/PartCategoryManager.php @@ -0,0 +1,42 @@ +<?php +namespace PartKeepr\PartCategory; + +use PartKeepr\Category\AbstractCategoryManager; +use DoctrineExtensions\NestedSet\NodeWrapper; +use PartKeepr\Util\SerializableException; +use PartKeepr\PartKeepr; + +class PartCategoryManager extends AbstractCategoryManager { + protected $categoryClass = "PartKeepr\PartCategory\PartCategory"; + + /** + * Deletes the given category ID. + * @param $id int The category id to delete + * @throws CategoryNotFoundException If the category wasn't found + */ + public function deleteCategory ($id) { + $category = $this->getCategory($id); + + try { + + if ($category->hasChildren()) { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains other categories."), $category->getNode()->getName())); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains other categories. Please move the categories or delete them first."), $category->getNode()->getName())); + + throw $exception; + } + + parent::deleteCategory($id); + } catch (\PDOException $e) { + if ($e->getCode() == "23000") { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains parts."), $category->getNode()->getName())); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains parts. Please move the parts to another category."), $category->getNode()->getName())); + + throw $exception; + } else { + throw $e; + } + } + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/PartCategory/PartCategoryService.php b/src/backend/PartKeepr/PartCategory/PartCategoryService.php @@ -0,0 +1,9 @@ +<?php +namespace PartKeepr\PartCategory; + +use PartKeepr\Category\AbstractCategoryService; + +class PartCategoryService extends AbstractCategoryService { + protected $categoryManagerClass = "PartKeepr\PartCategory\PartCategoryManager"; + protected $categoryClass = "PartKeepr\PartCategory\PartCategory"; +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/PartDistributor/PartDistributorManager.php b/src/backend/PartKeepr/PartDistributor/PartDistributorManager.php @@ -0,0 +1,74 @@ +<?php +namespace PartKeepr\PartDistributor; + +use PartKeepr\Util\Singleton, + PartKeepr\Manufacturer\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 @@ -0,0 +1,84 @@ +<?php +namespace PartKeepr\ManufacturerICLogo; + +use PartKeepr\Manufacturer\ManufacturerICLogo, + PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Manufacturer\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 @@ -0,0 +1,434 @@ +<?php +namespace PartKeepr; + +use Doctrine\Common\ClassLoader, + PartKeepr\SystemNotice\SystemNoticeManager, + Doctrine\ORM\Configuration, + Doctrine\ORM\EntityManager, + PartKeepr\Util\Configuration as PartKeeprConfiguration; + + + +class PartKeepr { + /** + * + * Contains the doctrine entity manager. + * @var Doctrine\ORM\EntityManager + */ + private static $entityManager = null; + + /** + * 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. + * @return nothing + */ + public static function initialize ($environment = null) { + self::initializeClassLoaders(); + self::initializeConfig($environment); + self::initializeDoctrine(); + } + + /** + * Initializes the doctrine class loader and sets up the + * directories. + * + * @param none + * @return nothing + */ + public static function initializeClassLoaders() { + require_once 'Doctrine/Common/ClassLoader.php'; + + + $classLoader = new ClassLoader('PartKeepr', self::getRootDirectory() . "/src/backend"); + $classLoader->register(); + + $classLoader = new ClassLoader('Doctrine\ORM'); + $classLoader->register(); + + $classLoader = new ClassLoader("Doctrine\DBAL\Migrations", self::getRootDirectory() ."/3rdparty/doctrine-migrations/lib"); + $classLoader->register(); + + $classLoader = new ClassLoader('Doctrine\DBAL'); + $classLoader->register(); + + $classLoader = new ClassLoader('Doctrine\Common'); + $classLoader->register(); + + $classLoader = new ClassLoader('Symfony', 'Doctrine'); + $classLoader->register(); + + $classLoader = new ClassLoader("DoctrineExtensions\NestedSet", self::getRootDirectory() ."/3rdparty/doctrine2-nestedset/lib"); + $classLoader->register(); + + + } + + /** + * 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. + * @return nothing + */ + public static function initializeConfig ($environment = null) { + if ($environment != null) { + include(self::getRootDirectory()."/config-$environment.php"); + } else { + include(self::getRootDirectory()."/config.php"); + } + + // 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 (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"] + ); + + } + } + + /** + * Initializes the doctrine framework and + * sets all required configuration options. + * + * @param none + * @return nothing + */ + public static function initializeDoctrine () { + $config = new Configuration; + + $driverImpl = $config->newDefaultAnnotationDriver( + array(__DIR__) + ); + $config->setMetadataDriverImpl($driverImpl); + + $connectionOptions = PartKeepr::createConnectionOptionsFromConfig(); + + if (extension_loaded("apc")) { + $cache = new \Doctrine\Common\Cache\ApcCache(); + } else { + $cache = new \Doctrine\Common\Cache\ArrayCache(); + } + + $config->setMetadataCacheImpl($cache); + + $config->setQueryCacheImpl($cache); + + $config->setProxyDir(self::getRootDirectory() . '/data/proxies'); + $config->setProxyNamespace('Proxies'); + $config->setEntityNamespaces(self::getEntityClasses()); + $config->setAutoGenerateProxyClasses(false); + + if (PartKeeprConfiguration::getOption("partkeepr.database.echo_sql_log", false) === true) { + $logger = new \Doctrine\DBAL\Logging\EchoSQLLogger(); + $config->setSQLLogger($logger); + } + + self::$entityManager = EntityManager::create($connectionOptions, $config); + } + + public static function createConnectionOptionsFromConfig () { + $connectionOptions = array(); + + $driver = PartKeeprConfiguration::getOption("partkeepr.database.driver"); + + switch ($driver) { + case "pdo_mysql": + case "pdo_pgsql": + case "pdo_oci": + case "oci8": + case "pdo_sqlsrv": + $connectionOptions["driver"] = $driver; + $connectionOptions["dbname"] = PartKeeprConfiguration::getOption("partkeepr.database.dbname", "partkeepr"); + $connectionOptions["user"] = PartKeeprConfiguration::getOption("partkeepr.database.username", "partkeepr"); + $connectionOptions["password"] = PartKeeprConfiguration::getOption("partkeepr.database.password", "partkeepr"); + $connectionOptions["charset"] = "utf8"; + /** + * Compatibility with older configuration files. We check for the key "hostname" as well as "host". + */ + if (PartKeeprConfiguration::getOption("partkeepr.database.hostname", null) !== null) { + $connectionOptions["host"] = PartKeeprConfiguration::getOption("partkeepr.database.hostname"); + } else { + $connectionOptions["host"] = PartKeeprConfiguration::getOption("partkeepr.database.host", "localhost"); + } + + + if (PartKeeprConfiguration::getOption("partkeepr.database.port") !== null) { + $connectionOptions["port"] = PartKeeprConfiguration::getOption("partkeepr.database.port"); + } + + if (PartKeeprConfiguration::getOption("partkeepr.database.mysql_socket", null) !== null) { + $connectionOptions["unix_socket"] = PartKeeprConfiguration::getOption("partkeepr.database.mysql_socket"); + } + break; + case "pdo_sqlite": + $connectionOptions["driver"] = $driver; + $connectionOptions["user"] = PartKeeprConfiguration::getOption("partkeepr.database.username", "partkeepr"); + $connectionOptions["password"] = PartKeeprConfiguration::getOption("partkeepr.database.password", "partkeepr"); + $connectionOptions["path"] = PartKeeprConfiguration::getOption("partkeepr.database.sqlite_path", PartKeepr::getRootDirectory() . "/data/partkeepr.sqlite"); + break; + default: + throw new \Exception(sprintf("Unknown driver %s", $driver)); + } + + return $connectionOptions; + } + + /** + * Returns the EntityManager. Shortcut for getEntityManager(). + * @return \Doctrine\ORM\EntityManager The EntityManager + */ + public static function getEM () { + return self::getEntityManager(); + } + + public static function getRootDirectory () { + return dirname(dirname(dirname(__DIR__))); + } + + /** + * Returns the EntityManager. + * @return Doctrine\ORM\EntityManager The EntityManager + */ + public static function getEntityManager () { + if (!self::$entityManager instanceof EntityManager) { + throw new Exception("No EntityManager found. Make sure you called initializeDoctrine() or initialize()."); + } + return self::$entityManager; + } + + /** + * 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\User\User', + 'PartKeepr\Session\Session', + + 'PartKeepr\Footprint\Footprint', + 'PartKeepr\Footprint\FootprintImage', + 'PartKeepr\Footprint\FootprintAttachment', + 'PartKeepr\FootprintCategory\FootprintCategory', + + 'PartKeepr\Part\Part', + 'PartKeepr\Part\PartUnit', + 'PartKeepr\Part\PartManufacturer', + 'PartKeepr\Part\PartDistributor', + 'PartKeepr\Part\PartImage', + 'PartKeepr\Part\PartAttachment', + 'PartKeepr\PartCategory\PartCategory', + + 'PartKeepr\Project\Project', + 'PartKeepr\Project\ProjectPart', + 'PartKeepr\Project\ProjectAttachment', + + 'PartKeepr\StorageLocation\StorageLocation', + 'PartKeepr\StorageLocation\StorageLocationImage', + + 'PartKeepr\Stock\StockEntry', + + 'PartKeepr\Manufacturer\Manufacturer', + 'PartKeepr\Manufacturer\ManufacturerICLogo', + + 'PartKeepr\Distributor\Distributor', + + 'PartKeepr\Image\Image', + 'PartKeepr\Image\CachedImage', + 'PartKeepr\TempImage\TempImage', + + 'PartKeepr\UploadedFile\TempUploadedFile', + + 'PartKeepr\Statistic\StatisticSnapshot', + 'PartKeepr\Statistic\StatisticSnapshotUnit', + 'PartKeepr\SiPrefix\SiPrefix', + 'PartKeepr\Unit\Unit', + 'PartKeepr\PartParameter\PartParameter', + + 'PartKeepr\TipOfTheDay\TipOfTheDay', + 'PartKeepr\TipOfTheDay\TipOfTheDayHistory', + 'PartKeepr\UserPreference\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; + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/PartKeeprVersion.php b/src/backend/PartKeepr/PartKeeprVersion.php @@ -0,0 +1,15 @@ +<?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/PartParameter/PartParameter.php b/src/backend/PartKeepr/PartParameter/PartParameter.php @@ -0,0 +1,247 @@ +<?php +namespace PartKeepr\PartParameter; + +use PartKeepr\PartKeepr, +PartKeepr\Util\Exceptions\OutOfRangeException, +PartKeepr\Unit\Unit, +PartKeepr\Part\Part, +PartKeepr\SiPrefix\SiPrefix; + + +/** + * This object represents a parameter. Each parameter can have an unit (defined by the class "Unit") associated with + * a numeric value. + * + * @Entity @HasLifecycleCallbacks + **/ +class PartParameter { + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + * @var integer + */ + private $id; + + /** + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + * The part this parameter is bound to + * @var Part + */ + private $part; + + /** + * The name of the parameter (e.g. Resistance, Voltage) + * @Column(type="string") + * @var string + */ + private $name; + + /** + * A description for this parameter + * @Column(type="string") + * @var string + */ + private $description; + + /** + * The unit for this type. May be null. + * + * @ManyToOne(targetEntity="PartKeepr\Unit\Unit") + * @var Unit + */ + private $unit; + + /** + * The value of the unit. Together with the prefix, it becomes the actual value. + * + * Example: If you have 10µ, the value field will contain "10", the prefix object is linked to the SiPrefix + * representing "µ" and the rawValue field will contain 0.000001 + * @Column(type="float") + * @var float + */ + private $value; + + /** + * The SiPrefix of the unit + * @ManyToOne(targetEntity="PartKeepr\SiPrefix\SiPrefix") + * @var object + */ + private $siPrefix; + + /** + * The raw value of the unit. + * @Column(type="float") + * @var float + */ + private $rawValue; + + /** + * Sets the name for this parameter + * @param string $name The name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name for this parameter + * @return string The name for this parameter + */ + public function getName () { + return $this->name; + } + + /** + * Sets the description for this parameter + * @param string $description The description + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * Sets the unit + * @param Unit $unit The unit to set + */ + public function setUnit (Unit $unit = null) { + $this->unit = $unit; + } + + /** + * Returns the unit + * @return Unit the unit + */ + public function getUnit () { + return $this->unit; + } + + /** + * Sets the part + * @param Part $part The part to set + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part + * @return Part the part + */ + public function getPart () { + return $this->part; + } + + /** + * Sets the value + * @param float $value The value to set + */ + public function setValue ($value) { + $this->value = $value; + + $this->recalculateRawValue(); + } + + /** + * Returns the value + * @return float The value + */ + public function getValue () { + return $this->value; + } + + /** + * Sets the si prefix for this parameter + * @param SiPrefix $prefix The prefix to set, or null + */ + public function setSiPrefix (SiPrefix $prefix = null) { + $this->siPrefix = $prefix; + + $this->recalculateRawValue(); + } + + /** + * Returns the si prefix for this parameter + * @return SiPrefix the si prefix or null + */ + public function getSiPrefix () { + return $this->siPrefix; + } + + /** + * Returns the ID for this object. + * @param none + * @return int The ID for this object + */ + public function getId () { + return $this->id; + } + + private function recalculateRawValue () { + if (is_object($this->getSiPrefix())) { + $power = $this->getSiPrefix()->getPower(); + } else { + $power = 0; + } + + $this->rawValue = $this->getValue() * pow(10, $power); + } + + /** + * Returns the data of this object in a serialized form. + * @return array The result array + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "description" => $this->getDescription(), + "value" => $this->getValue(), + "part_id" => $this->getPart()->getId(), + "siprefix_id" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getId() : null, + "prefixedValue" => array( + /* We duplicate most data because of strange ExtJS stuff... */ + "value" => $this->getValue(), + "power" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getPower() : 0, + "symbol" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getSymbol() : "", + "siprefix_id" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getId() : null + ), + "unit_id" => is_object($this->getUnit()) ? $this->getUnit()->getId() : null + ); + } + + /** + * Deserializes the part parameter + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "description": + $this->setDescription($value); + break; + case "value": + $this->setValue($value); + break; + case "siprefix_id": + $prefix = SiPrefix::loadById($value); + $this->setSiPrefix($prefix); + break; + case "unit_id": + $unit = Unit::loadById($value); + $this->setUnit($unit); + break; + } + } + } +} diff --git a/src/backend/PartKeepr/PartUnit/PartUnitManager.php b/src/backend/PartKeepr/PartUnit/PartUnitManager.php @@ -0,0 +1,106 @@ +<?php +namespace PartKeepr\PartUnit; + +use PartKeepr\Util\Singleton, + PartKeepr\Part\PartUnit, + PartKeepr\PartKeepr, + PartKeepr\Category\CategoryManager, + PartKeepr\PartUnit\Exceptions\PartUnitNotFoundException; + +class PartUnitManager extends Singleton { + public function getPartUnits ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st.id, st.name, st.shortName, st.is_default AS default")->from("PartKeepr\Part\PartUnit","st"); + + if ($filter != "") { + $qb = $qb->where("LOWER(st.name) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + foreach ($result as $key => $row) { + foreach ($row as $rowkey => $column) { + if ($rowkey == "default") { + if ($column == 0) { + $result[$key][$rowkey] = false; + } else { + $result[$key][$rowkey] = true; + } + } + } + } + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\Part\PartUnit","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + public function getPartUnit ($id) { + $partUnit = PartKeepr::getEM()->find("PartKeepr\Part\PartUnit", $id); + + if ($partUnit) { + return $partUnit; + } else { + throw new PartUnitNotFoundException(); + } + } + + public function deletePartUnit ($id) { + $partUnit = $this->getPartUnit($id); + + PartKeepr::getEM()->remove($partUnit); + PartKeepr::getEM()->flush(); + } + + /** + * Returns the default part unit for this system + * + * @param none + * @return PartUnit The default part unit for this system + */ + public function getDefaultPartUnit () { + $dql = 'SELECT pu FROM PartKeepr\Part\PartUnit pu WHERE pu.is_default = :default'; + return PartKeepr::getEM()->createQuery($dql)->setParameter("default", true)->getSingleResult(); + } + + public function setDefaultPartUnit ($id) { + PartKeepr::getEM()->beginTransaction(); + + $dql = 'UPDATE PartKeepr\Part\PartUnit pu SET pu.is_default = :default WHERE pu.id = :id'; + PartKeepr::getEM()->createQuery($dql)->setParameter("id", $id)->setParameter("default", true, \PDO::PARAM_BOOL)->execute(); + + $dql = 'UPDATE PartKeepr\Part\PartUnit pu SET pu.is_default = :default WHERE pu.id != :id'; + PartKeepr::getEM()->createQuery($dql)->setParameter("id", $id)->setParameter("default", false, \PDO::PARAM_BOOL)->execute(); + + PartKeepr::getEM()->commit(); + } + + public function getUnitCounts () { + $dql = 'SELECT SUM(p.stockLevel) AS stockLevel, pu.id AS puid FROM PartKeepr\Part\PartUnit pu LEFT JOIN pu.parts p GROUP BY pu.id'; + + $result = PartKeepr::getEM()->createQuery($dql)->getResult(); + + return $result; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/PartUnit/PartUnitService.php b/src/backend/PartKeepr/PartUnit/PartUnitService.php @@ -0,0 +1,72 @@ +<?php +namespace PartKeepr\PartUnit; +use PartKeepr\Service\RestfulService; + +use PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Part\PartUnit, + PartKeepr\Session\SessionManager; + +class PartUnitService extends Service implements RestfulService { + public function get () { + if ($this->hasParameter("id")) { + return array("data" => PartUnitManager::getInstance()->getPartUnit($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "name", + "direction" => "ASC"); + } + return PartUnitManager::getInstance()->getPartUnits( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + public function create () { + $this->requireParameter("name"); + + $partUnit = new PartUnit; + $partUnit->deserialize($this->getParameters()); + + PartKeepr::getEM()->persist($partUnit); + PartKeepr::getEM()->flush(); + + return array("data" => $partUnit->serialize()); + } + + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + + $partUnit = PartUnitManager::getInstance()->getPartUnit($this->getParameter("id")); + $partUnit->deserialize($this->getParameters()); + PartKeepr::getEM()->flush(); + + return array("data" => $partUnit->serialize()); + + } + + public function destroy () { + $this->requireParameter("id"); + + PartUnitManager::getInstance()->deletePartUnit($this->getParameter("id")); + + return array("data" => null); + } + + public function setDefault () { + $this->requireParameter("id"); + + $partUnit = PartUnitManager::getInstance()->setDefaultPartUnit($this->getParameter("id")); + + return array("data" => null); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Ping/PingService.php b/src/backend/PartKeepr/Ping/PingService.php @@ -0,0 +1,19 @@ +<?php +namespace PartKeepr\Ping; +use PartKeepr\Service\AnonService; + +use PartKeepr\Service\Service, + PartKeepr\PartKeepr; + +class PingService extends AnonService { + /** + * Simple test call to verify if the service layer is reachable. + * + * This is used for the PartKeeprMobile client to verify if the URL + * is entered correctly. + */ + public function ping () { + return "pong"; + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Project/Project.php b/src/backend/PartKeepr/Project/Project.php @@ -0,0 +1,161 @@ +<?php +namespace PartKeepr\Project; + +use PartKeepr\User\User, + PartKeepr\Util\Serializable, + PartKeepr\Util\Deserializable, + PartKeepr\Util\BaseEntity; + +/** + * Represents a part in the database. The heart of our project. Handle with care! + * @Entity **/ +class Project extends BaseEntity implements Serializable, Deserializable { + /** + * Specifies the name of the project + * @Column(type="string") + */ + private $name; + + /** + * Specifies the user this project belongs to + * @ManyToOne(targetEntity="PartKeepr\User\User") + */ + private $user; + + /** + * Holds the parts needed for this project + * @OneToMany(targetEntity="PartKeepr\Project\ProjectPart",mappedBy="project",cascade={"persist", "remove"}) + * @var ArrayCollection + */ + private $parts; + + /** + * Holds the description of this project + * @Column(type="string",nullable=true) + * @var string + */ + private $description; + + /** + * Holds the project attachments + * @OneToMany(targetEntity="PartKeepr\Project\ProjectAttachment",mappedBy="project",cascade={"persist", "remove"}) + * @var ProjectAttachment + */ + private $attachments; + + + /** + * Constructs a new project + */ + public function __construct () { + $this->parts = new \Doctrine\Common\Collections\ArrayCollection(); + $this->attachments = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Sets the user for this project + * @param User $user + */ + public function setUser (User $user) { + $this->user = $user; + } + + /** + * Gets the user for this project + * @return User + */ + public function getUser () { + return $this->user; + } + + /** + * Sets the name for this project + * @param string $name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name of this project + */ + public function getName () { + return $this->name; + } + + /** + * Sets the description of this project + * @param string $description The description to set + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description of this project + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * Returns the parts array + * @return ArrayCollection An array of ProjectPart objects + */ + public function getParts () { + return $this->parts; + } + + /** + * Returns the attachments for this project + * @return ArrayCollection The attachments + */ + public function getAttachments () { + return $this->attachments; + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "description" => $this->getDescription(), + "parts" => $this->serializeChildren($this->getParts()), + "attachments" => $this->serializeChildren($this->getAttachments()) + ); + } + + /** + * Deserializes the project + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "description": + $this->setDescription($value); + break; + case "parts": + $this->deserializeChildren($value, $this->getParts(), "PartKeepr\Project\ProjectPart"); + foreach ($this->getParts() as $part) { + $part->setProject($this); + } + break; + case "attachments": + $this->deserializeChildren($value, $this->getAttachments(), "PartKeepr\Project\ProjectAttachment"); + foreach ($this->getAttachments() as $attachment) { + $attachment->setProject($this); + } + break; + } + } + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Project/ProjectAttachment.php b/src/backend/PartKeepr/Project/ProjectAttachment.php @@ -0,0 +1,101 @@ +<?php +namespace PartKeepr\Project; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\UploadedFile\UploadedFile; + +/** + * Holds a project attachment + * @Entity + **/ +class ProjectAttachment extends UploadedFile implements Serializable, Deserializable { + /** + * The description of this attachment + * @Column(type="text") + * @var string + */ + private $description; + + /** + * Creates a new project attachment + */ + public function __construct () { + parent::__construct(); + $this->setType("ProjectAttachment"); + } + /** + * The project object + * @ManyToOne(targetEntity="PartKeepr\Project\Project") + * @var Project + */ + private $project = null; + + /** + * Sets the project + * @param Project $project The project to set + */ + public function setProject (Project $project) { + $this->project = $project; + } + + /** + * Returns the roject + * @return Project the project + */ + public function getProject () { + return $this->project; + } + + /** + * Sets the description for this attachment + * @param string $description The attachment description + */ + public function setDescription ($description) { + $this->description = $description; + } + + /** + * Returns the description for this attachment + * @return string The description + */ + public function getDescription () { + return $this->description; + } + + /** + * + * Serializes this project attachment + * @return array The serialized project attachment + */ + public function serialize () { + return array( + "id" => $this->getId(), + "project_id" => $this->getProject()->getId(), + "originalFilename" => $this->getOriginalFilename(), + "mimetype" => $this->getMimetype(), + "extension" => $this->getExtension(), + "size" => $this->getSize(), + "description" => $this->getDescription()); + } + + /** + * Deserializes the project attachment + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + if (array_key_exists("id", $parameters)) { + if (substr($parameters["id"], 0, 4) === "TMP:") { + $this->replaceFromTemporaryFile($parameters["id"]); + } + } + + foreach ($parameters as $key => $value) { + switch ($key) { + case "description": + $this->setDescription($value); + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Project/ProjectManager.php b/src/backend/PartKeepr/Project/ProjectManager.php @@ -0,0 +1,33 @@ +<?php +namespace PartKeepr\Project; + +use PartKeepr\Manager\AbstractManager, + PartKeepr\Project\Project, + PartKeepr\PartKeepr; + +class ProjectManager 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\Project\Project'; + } + + /** + * 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", "name", "description"); + } + + /** + * Returns the default sort field + * + * @return string The default sort field + */ + public function getDefaultSortField () { + return "name"; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Project/ProjectPart.php b/src/backend/PartKeepr/Project/ProjectPart.php @@ -0,0 +1,136 @@ +<?php +namespace PartKeepr\Project; + +use PartKeepr\Part\Part, + PartKeepr\Util\Serializable, + PartKeepr\Util\Deserializable, + PartKeepr\Util\BaseEntity; + +/** + * Represents a part in the database. The heart of our project. Handle with care! + * @Entity **/ +class ProjectPart extends BaseEntity implements Serializable, Deserializable { + /** + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + */ + private $part; + + /** + * Specifies the amount of parts + * @Column(type="integer") + */ + private $quantity; + + /** + * Specifies the project which belongs to this project part + * @ManyToOne(targetEntity="PartKeepr\Project\Project") + */ + private $project; + + /** + * Specifies the remarks for this entry + * @Column(type="string",nullable=true) + */ + private $remarks; + + /** + * Sets the part which belongs to this entry + * @param Part $part + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part which belongs to this entry + * @return Part + */ + public function getPart () { + return $this->part; + } + + /** + * Sets the quantity for this entry + * @param int $quantity + */ + public function setQuantity ($quantity) { + $this->quantity = intval($quantity); + } + + /** + * Returns the quantity for this project + * @return int the amount of parts needed + */ + public function getQuantity () { + return $this->quantity; + } + + /** + * Sets the project assigned to this entry + * @param Project $project + */ + public function setProject (Project $project) { + $this->project = $project; + } + + /** + * Returns the project assigned to this entry + * @return Project + */ + public function getProject () { + return $this->project; + } + + /** + * Sets the remarks for this entry + * @param string $remarks + */ + public function setRemarks ($remarks) { + $this->remarks = $remarks; + } + + /** + * Returns the remarks for this entry + * @return string + */ + public function getRemarks () { + return $this->remarks; + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "id" => $this->getId(), + "quantity" => $this->getQuantity(), + "part_id" => is_object($this->getPart()) ? $this->getPart()->getId() : 0, + "part_name" => is_object($this->getPart()) ? $this->getPart()->getName() : 0, + "project_id" => $this->getProject()->getId(), + "remarks" => $this->getRemarks() + ); + } + + /** + * Deserializes the project + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "remarks": + $this->setRemarks($value); + break; + case "quantity": + $this->setQuantity($value); + break; + case "part_id": + $part = Part::loadById($value); + $this->setPart($part); + break; + } + } + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Project/ProjectService.php b/src/backend/PartKeepr/Project/ProjectService.php @@ -0,0 +1,64 @@ +<?php +namespace PartKeepr\Project; + +use PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\Project\ProjectManager, + PartKeepr\PartKeepr, + PartKeepr\Manager\ManagerFilter; + +class ProjectService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return array("data" => ProjectManager::getInstance()->getEntity($this->getParameter("id"))->serialize()); + } else { + $parameters = new ManagerFilter($this); + $parameters->setFilterField("name"); + return ProjectManager::getInstance()->getList($parameters); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $this->requireParameter("name"); + + $entity = ProjectManager::getInstance()->createEntity($this->getParameters()); + + return array("data" => $entity->serialize()); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + $entity = ProjectManager::getInstance()->getEntity($this->getParameter("id")); + $entity->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $entity->serialize()); + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + $this->requireParameter("id"); + + ProjectManager::getInstance()->deleteEntity($this->getParameter("id")); + + return array("data" => null); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/ProjectAttachment/ProjectAttachmentManager.php b/src/backend/PartKeepr/ProjectAttachment/ProjectAttachmentManager.php @@ -0,0 +1,68 @@ +<?php +namespace PartKeepr\ProjectAttachment; + +use PartKeepr\Util\Singleton, + PartKeepr\Project\Project, + PartKeepr\PartKeepr; + +class ProjectAttachmentManager extends Singleton { + /** + * Returns a list of project attachments + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter The project id + */ + public function getProjectAttachments ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st")->from("PartKeepr\Project\ProjectAttachment","st") + ->leftJoin('st.project', "fp"); + + if ($filter != "") { + $project = Project::loadById($filter); + $qb = $qb->where("st.project = :project"); + $qb->setParameter("project", $project); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\Project\ProjectAttachment","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("st.project = :project"); + $totalQueryBuilder->setParameter("project", $project); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + $aData = array(); + foreach ($result as $item) { + $aData[] = $item->serialize(); + } + return array("data" => $aData, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Returns a project attachment by id + * @param int $id The project attachment id + */ + public function getProjectAttachment ($id) { + return ProjectAttachment::loadById($id); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/ProjectAttachment/ProjectAttachmentService.php b/src/backend/PartKeepr/ProjectAttachment/ProjectAttachmentService.php @@ -0,0 +1,102 @@ +<?php +namespace PartKeepr\ProjectAttachment; + +use PartKeepr\Project\ProjectAttachment, + PartKeepr\UploadedFile\TempUploadedFile, + PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Project\Project, + PartKeepr\Session\SessionManager; + +class ProjectAttachmentService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return ProjectAttachmentManager::getInstance()->getProjectAttachment($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"] == "project_id") { + if (array_key_exists("value", $item)) { + $filter = $item["value"]; + } + } + } + } + } + return ProjectAttachmentManager::getInstance()->getProjectAttachments( + $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); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + $this->requireParameter("tmp_id"); + $this->requireParameter("project_id"); + + $tmpImage = TempUploadedFile::loadById($this->getParameter("tmp_id")); + + $file = new ProjectAttachment(); + + $project = Project::loadById($this->getParameter("project_id")); + + $file->setProject($project); + $file->replace($tmpImage->getFilename()); + $file->setOriginalFilename($tmpImage->getOriginalFilename()); + $file->setDescription($this->getParameter("description")); + PartKeepr::getEM()->persist($file); + PartKeepr::getEM()->flush(); + + return $file->serialize(); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + $this->requireParameter("id"); + + $file = ProjectAttachment::loadById($this->getParameter("id")); + + PartKeepr::getEM()->remove($file); + PartKeepr::getEM()->flush(); + + return array("data" => null); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/ProjectReport/ProjectReportService.php b/src/backend/PartKeepr/ProjectReport/ProjectReportService.php @@ -0,0 +1,97 @@ +<?php +namespace PartKeepr\ProjectReport; + +use PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\Project\ProjectManager, + PartKeepr\PartKeepr, + PartKeepr\Part\Part, + PartKeepr\Manager\ManagerFilter; + +class ProjectReportService extends Service implements RestfulService { + /** + * Returns a project report. + * + * The input format is an array with the following keys per entry: + * - project: The project ID + * - amount: Specifies how many copies of the project need to be reported + * + * The output format is an array which contains the following keys: + * - quantity: The overall quantity of parts needed (for a specific part) + * - part: The serialized part entity + * - storageLocation_name: The storage location name + * - available: The overall amount of available parts + * - sum_order: Always set to 0 because calculation happens in the frontend + * + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + $reports = json_decode($this->getParameter("reports"), true); + + $aPartResults = array(); + + // Loop over all reports and calculate the overall quantities + foreach ($reports as $report) { + $dql = "SELECT pp.quantity, pro.name AS projectname, pp.remarks, p.id FROM "; + $dql .= "PartKeepr\Project\ProjectPart pp JOIN pp.part p "; + $dql .= "JOIN pp.project pro WHERE pp.project = :project"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("project", $report["project"]); + + foreach ($query->getArrayResult() as $result) { + $part = Part::loadById($result["id"]); + + if (array_key_exists($result["id"], $aPartResults)) { + // Only update the quantity of the part + $aPartResults[$result["id"]]["quantity"] += $result["quantity"] * $report["amount"]; + $aPartResults[$result["id"]]["projects"][] = $result["projectname"]; + + if ($result["remarks"] != "") { + $aPartResults[$result["id"]]["remarks"][] = $result["projectname"]. ": " .$result["remarks"]; + } + } else { + // Create a full resultset + $aPartResults[$result["id"]] = array( + "quantity" => $result["quantity"] * $report["amount"], + "part" => array("response" => array("totalCount" => 1, "data" => $part->serialize())), + "storageLocation_name" => $part->getStorageLocation()->getName(), + "available" => $part->getStockLevel(), + "sum_order" => 0, + "projects" => array($result["projectname"]), + "remarks" => array() + ); + + if ($result["remarks"] != "") { + $aPartResults[$result["id"]]["remarks"] = array($result["projectname"]. ": " .$result["remarks"]); + } + } + } + } + + $aFinalResult = array(); + + // Iterate over all results and calculate how many parts are missing + foreach ($aPartResults as $key => $partResult) { + $missing = $partResult["quantity"] - $partResult["available"]; + + if ($missing < 0) { + $missing = 0; + } + + $partResult["missing"] = $missing; + $partResult["remarks"] = implode(", ", $partResult["remarks"]); + $partResult["projects"] = implode(", ", $partResult["projects"]); + + $aFinalResult[] = $partResult; + } + + return array("data" => $aFinalResult); + } + + public function create () {} + + public function update () {} + + public function destroy () {} +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/REST/ApplicationController.php b/src/backend/PartKeepr/REST/ApplicationController.php @@ -0,0 +1,42 @@ +<?php +namespace PartKeepr\REST; + +// Class taken over from the Sencha example +class ApplicationController { + public $request, $id, $params; + + /** + * dispatch + * Dispatch request to appropriate controller-action by convention according to the HTTP method. + */ + public function dispatch($request) { + $this->request = $request; + $this->id = $request->id; + $this->params = $request->params; + + if ($request->isRestful()) { + return $this->dispatchRestful(); + } + if ($request->action) { + return $this->{$request->action}(); + } + } + + protected function dispatchRestful() { + switch ($this->request->method) { + case 'GET': + return $this->view(); + break; + case 'POST': + return $this->create(); + break; + case 'PUT': + return $this->update(); + break; + case 'DELETE': + return $this->destroy(); + break; + } + } +} + diff --git a/src/backend/PartKeepr/REST/Model.php b/src/backend/PartKeepr/REST/Model.php @@ -0,0 +1,71 @@ +<?php +namespace PartKeepr\REST; + +// Class taken over from the Sencha example +class Model { + public $id, $attributes; + static function create($params) { + $obj = new self(get_object_vars($params)); + $obj->save(); + return $obj; + } + static function find($id) { + global $dbh; + $found = null; + foreach ($dbh->rs() as $rec) { + if ($rec['id'] == $id) { + $found = new self($rec); + break; + } + } + return $found; + } + static function update($id, $params) { + global $dbh; + $rec = self::find($id); + + if ($rec == null) { + return $rec; + } + $rs = $dbh->rs(); + + foreach ($rs as $idx => $row) { + if ($row['id'] == $id) { + $rec->attributes = array_merge($rec->attributes, get_object_vars($params)); + $dbh->update($idx, $rec->attributes); + break; + } + } + return $rec; + } + static function destroy($id) { + global $dbh; + $rec = null; + $rs = $dbh->rs(); + foreach ($rs as $idx => $row) { + if ($row['id'] == $id) { + $rec = new self($dbh->destroy($idx)); + break; + } + } + return $rec; + } + static function all() { + global $dbh; + return $dbh->rs(); + } + + public function __construct($params) { + $this->id = isset($params['id']) ? $params['id'] : null; + $this->attributes = $params; + } + public function save() { + global $dbh; + $this->attributes['id'] = $dbh->pk(); + $dbh->insert($this->attributes); + } + public function to_hash() { + return $this->attributes; + } +} + diff --git a/src/backend/PartKeepr/REST/Request.php b/src/backend/PartKeepr/REST/Request.php @@ -0,0 +1,115 @@ +<?php +namespace PartKeepr\REST; + +// Class taken over from the Sencha example +class Request { + public $restful, $method, $controller, $action, $id, $params; + + public function __construct($params) { + $this->restful = (isset($params["restful"])) ? $params["restful"] : false; + $this->method = $_SERVER["REQUEST_METHOD"]; + $this->parseRequest(); + } + public function isRestful() { + return $this->restful; + } + + public function getMethod () { + return $this->method; + } + + public function getParams () { + if ($this->params === null) { + $this->params = array(); + } + + if ($this->id !== null) { + $this->params["id"] = $this->id; + } + + $this->params = array_merge($_REQUEST, $this->params); + return $this->params; + } + + public function getService () { + if ($this->controller == "") { + $this->controller = $_REQUEST["service"]; + } + + $serviceName = $this->controller."Service"; + $namespace = 'PartKeepr\\'; + $cat = $this->controller . "\\"; + $fullName= $namespace . $cat . $serviceName; + + $class = new $fullName($this->getParams()); + + return $class; + } + + public function getAction () { + return $this->action; + } + + protected function parseRequest() { + if ($this->method == 'PUT') { // <-- Have to jump through hoops to get PUT data + $raw = ''; + $httpContent = fopen('php://input', 'r'); + while ($kb = fread($httpContent, 1024)) { + $raw .= $kb; + } + fclose($httpContent); + $params = array(); + parse_str($raw, $params); + + if (isset($params['data'])) { + $this->params = json_decode($params['data'], true); + } else { + $params = json_decode($raw, true); + $this->params = $params; + } + } else { + // grab JSON data if there... + $this->params = (isset($_REQUEST['data'])) ? json_decode($_REQUEST['data'], true) : null; + + if (isset($_REQUEST['data'])) { + $this->params = json_decode($_REQUEST['data'], true); + } else { + $raw = ''; + $httpContent = fopen('php://input', 'r'); + while ($kb = fread($httpContent, 1024)) { + $raw .= $kb; + } + $params = json_decode($raw, true); + if ($params) { + $this->params = $params; + } + } + + } + // Quickndirty PATH_INFO parser + if (isset($_SERVER["PATH_INFO"])){ + $cai = '/^\/([A-Za-z]+\w)\/([A-Za-z]+\w)\/([0-9]+)$/'; // /controller/action/id + $ca = '/^\/([A-Za-z]+\w)\/([A-Za-z]+)$/'; // /controller/action + $ci = '/^\/([A-Za-z]+\w)\/([0-9]+)$/'; // /controller/id + $c = '/^\/([A-Za-z]+\w)$/'; // /controller + $i = '/^\/([0-9]+)$/'; // /id + $matches = array(); + if (preg_match($cai, $_SERVER["PATH_INFO"], $matches)) { + $this->controller = $matches[1]; + $this->action = $matches[2]; + $this->id = $matches[3]; + } else if (preg_match($ca, $_SERVER["PATH_INFO"], $matches)) { + $this->controller = $matches[1]; + $this->action = $matches[2]; + } else if (preg_match($ci, $_SERVER["PATH_INFO"], $matches)) { + $this->controller = $matches[1]; + $this->id = $matches[2]; + } else if (preg_match($c, $_SERVER["PATH_INFO"], $matches)) { + $this->controller = $matches[1]; + } else if (preg_match($i, $_SERVER["PATH_INFO"], $matches)) { + $this->id = $matches[1]; + } + } + } +} + diff --git a/src/backend/PartKeepr/REST/Response.php b/src/backend/PartKeepr/REST/Response.php @@ -0,0 +1,21 @@ +<?php +namespace PartKeepr\REST; + +// Class taken over from the Sencha example +class Response { + public $success, $data, $message, $errors, $tid, $trace; + + public function __construct($params = array()) { + $this->success = isset($params["success"]) ? $params["success"] : false; + $this->message = isset($params["message"]) ? $params["message"] : ''; + $this->data = isset($params["data"]) ? $params["data"] : array(); + } + + public function to_json() { + return json_encode(array( + 'success' => $this->success, + 'message' => $this->message, + 'data' => $this->data + )); + } +} diff --git a/src/backend/PartKeepr/Service/AdminService.php b/src/backend/PartKeepr/Service/AdminService.php @@ -0,0 +1,14 @@ +<?php +namespace PartKeepr\Service; + +use PartKeepr\Session\SessionManager; + +class AdminService extends Service { + public function mayCall ($call) { + if (SessionManager::getCurrentSession()->getUser()->isAdmin()) { + return true; + } else { + return false; + } + } +} diff --git a/src/backend/PartKeepr/Service/AnonService.php b/src/backend/PartKeepr/Service/AnonService.php @@ -0,0 +1,6 @@ +<?php +namespace PartKeepr\Service; + +class AnonService extends Service { + +} diff --git a/src/backend/PartKeepr/Service/Exceptions/ServiceException.php b/src/backend/PartKeepr/Service/Exceptions/ServiceException.php @@ -0,0 +1,6 @@ +<?php +namespace PartKeepr\Service\Exceptions; + +use PartKeepr\Util\SerializableException; + +class ServiceException extends SerializableException {} diff --git a/src/backend/PartKeepr/Service/RestfulService.php b/src/backend/PartKeepr/Service/RestfulService.php @@ -0,0 +1,9 @@ +<?php +namespace PartKeepr\Service; + +interface RestfulService { + public function get (); + public function create (); + public function update (); + public function destroy (); +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Service/Service.php b/src/backend/PartKeepr/Service/Service.php @@ -0,0 +1,110 @@ +<?php +namespace PartKeepr\Service; + +use PartKeepr\User\User, + PartKeepr\Session\Session, + PartKeepr\Session\SessionManager, + PartKeepr\Service\Exceptions\ServiceException; + +class Service { + private $params; + + public function __construct (Array $params) { + $this->params = $params; + } + + public function mayCall ($call) { + if (SessionManager::getCurrentSession()->getUser() === null) { + return false; + } else { + /* @todo: Implement permission checking */ + return true; + } + + + } + + protected function requireParameter ($name) { + if (!$this->hasParameter($name)) { + throw new ServiceException(sprintf("Parameter %s is required.", $name)); + } + } + + public function getParameter ($name, $default = null) { + if (!$this->hasParameter($name)) { + return $default; + } else { + return $this->params[$name]; + } + } + + /** + * Returns all parameters passed to the service + * @return array An array with all parameters (key=>value format) + */ + public function getParameters () { + return $this->params; + } + + /** + * Returns the current user for this session + * + * @return User The user + */ + public function getUser () { + return SessionManager::getCurrentSession()->getUser(); + } + + /** + * Checks if the environment has an active, logged in user. + * + * @param none + * @return boolean True if a logged in user exists, false otherwise + */ + public function hasUser () { + if (!$this->hasSession()) { + return false; + } + + var_dump($this->getUser()); + if ($this->getUser() !== null) { + return true; + } else { + return false; + } + } + + /** + * Checks if there is an active session. + * + * @param none + * @return boolean true if an active session exists, false otherwise + */ + public function hasSession () { + return SessionManager::hasSession(); + } + + public function hasParameter ($name) { + if (array_key_exists($name, $this->params)) { + return true; + } else { + return false; + } + } + + public function hasHeader ($name) { + $targetName = "HTTP_".strtoupper($name); + + return array_key_exists($targetName, $_SERVER); + } + + public function getHeader ($name) { + $targetName = "HTTP_".strtoupper($name); + + if (array_key_exists($targetName, $_SERVER)) { + return $_SERVER[$targetName]; + } else { + throw new \Exception("Header ".$targetName." not found"); + } + } +} diff --git a/src/backend/PartKeepr/Service/ServiceManager.php b/src/backend/PartKeepr/Service/ServiceManager.php @@ -0,0 +1,126 @@ +<?php +namespace PartKeepr\Service; + +use PartKeepr\Session\SessionManager, + PartKeepr\Service\Exceptions\ServiceException, + PartKeepr\PartKeepr, + PartKeepr\User\User, + PartKeepr\User\UserManager, + PartKeepr\REST\Request; + +class ServiceManager { + + public static function sendHeaders () { + header("Content-Type: text/html; charset=UTF-8"); + header("Cache-Control: no-cache, must-revalidate"); + header("Access-Control-Allow-Origin: *"); + header("Access-Control-Allow-Headers: lang,call,service,X-Requested-With,X-PartKeepr-Locale,X-PartKeepr-Name,X-PartKeepr-Call"); + } + + public static function call () { + + $request = new Request(array('restful' => true)); + $service = $request->getService(); + + if ($service->hasHeader("call")) { + $call = $service->getHeader("call"); + } elseif (array_key_exists("call", $_REQUEST) && $_REQUEST["call"] != "") { + $call = $_REQUEST["call"]; + } elseif ($request->action != "") { + $call = $request->action; + } else { + switch (strtoupper($request->getMethod())) { + case "POST": + $call = "create"; + break; + case "GET": + $call = "get"; + break; + case "PUT": + $call = "update"; + break; + case "DELETE": + $call = "destroy"; + break; + default: + $call = $request->getMethod(); + break; + } + } + + $allowCall = true; + + if (!is_subclass_of($service, "PartKeepr\\Service\\AnonService")) { + $session = null; + $sessionid = false; + + $sessionid = self::getSession($service); + + + if ($sessionid === null) + { + $session = SessionManager::getInstance()->startSession(); + throw new ServiceException("You called a non-anonymous service, but did not pass the 'session' parameter."); + } else { + $session = SessionManager::getInstance()->resumeSession($sessionid); + } + + if (!$service->mayCall($call)) { + $allowCall = false; + } + } + + if (!$allowCall) { + throw new ServiceException("Permission denied"); + } + + if (!method_exists($service, $call)) { + throw new \Exception(sprintf("The service %s doesn't implement %s", get_class($service), $call)); + } + $result = $service->$call(); + + PartKeepr::getEM()->flush(); + + return $result; + + } + + private static function getSession ($service) { + if ($service->hasHeader("username") && $service->hasHeader("password") && !$service->hasHeader("session")) { + return self::authenticateByUsername($service->getHeader("username"), $service->getHeader("password")); + } + + if (array_key_exists("username", $_REQUEST) && array_key_exists("password", $_REQUEST) && !array_key_exists("session", $_REQUEST)) { + return self::authenticateByUsername($_REQUEST["username"], $_REQUEST["password"]); + } + + if ($service->hasHeader("session")) { + return $service->getHeader("session"); + } + + if (array_key_exists("session", $_REQUEST)) { + return $_REQUEST["session"]; + } + } + + private static function authenticateByUsername ($username, $password) { + /* Build a temporary user */ + $user = new User; + $user->setRawUsername($username); + $user->setHashedPassword($password); + + $authenticatedUser = UserManager::getInstance()->authenticate($user); + + if ($authenticatedUser !== false) { + /* Start Session */ + $session = SessionManager::getInstance()->startSession($authenticatedUser); + + return $session->getSessionID(); + } else { + throw new InvalidLoginDataException(); + } + } + +} + +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Session/Exceptions/SessionNotFoundException.php b/src/backend/PartKeepr/Session/Exceptions/SessionNotFoundException.php @@ -0,0 +1,10 @@ +<?php +namespace PartKeepr\Session\Exceptions; + +use PartKeepr\Util\SerializableException; + +class SessionNotFoundException extends SerializableException { + public function __construct ($id) { + parent::__construct("The session with the id $id could not be found"); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Session/Session.php b/src/backend/PartKeepr/Session/Session.php @@ -0,0 +1,59 @@ +<?php +namespace PartKeepr\Session; + +use PartKeepr\User\User, + PartKeepr\PartKeepr; + +/** @Entity */ +class Session { + + /** @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + */ + private $id; + + /** @Column(length=50) */ + private $sessionid; + + /** + * @ManyToOne(targetEntity="PartKeepr\User\User") + */ + private $user; + + public function __construct () { + + } + + public function start () { + session_start(); + session_regenerate_id(); + session_destroy(); + unset($_SESSION); + session_start(); + + $query = PartKeepr::getEM()->createQuery("DELETE FROM PartKeepr\\Session\\Session s WHERE s.sessionid = :session"); + $query->setParameter("session", session_id()); + $query->execute(); + + $this->sessionid = session_id(); + } + + public function getSessionID () { + return $this->sessionid; + } + + public function resume () { + session_id($this->sessionid); + session_start(); + } + + public function getUser () { + return $this->user; + } + + public function setUser (User $user = null) { + $this->user = $user; + } + +} +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Session/SessionManager.php b/src/backend/PartKeepr/Session/SessionManager.php @@ -0,0 +1,68 @@ +<?php +namespace PartKeepr\Session; + +use PartKeepr\Util\Singleton, + PartKeepr\User\User, + PartKeepr\Session\Exceptions\SessionNotFoundException, + PartKeepr\PartKeepr; + +class SessionManager extends Singleton { + public static $currentSession = null; + + public static function getCurrentSession () { + return self::$currentSession; + } + + public static function hasSession () { + if (self::$currentSession !== null) { + return true; + } else { + return false; + } + } + + public function startSession (User $user = null) { + if (is_object($user)) { + try { + $query = PartKeepr::getEM()->createQuery("SELECT s FROM PartKeepr\\Session\\Session s WHERE s.user = :user"); + $query->setParameter("user", $user); + $query->execute(); + + $session = $query->getSingleResult(); + $session->resume(); + } catch (\Exception $e) { + $session = new Session; + $session->setUser($user); + $session->start(); + PartKeepr::getEM()->persist($session); + } + } else { + $session = new Session; + $session->setUser(null); + $session->start(); + PartKeepr::getEM()->persist($session); + } + + PartKeepr::getEM()->flush(); + + self::$currentSession = $session; + + return $session; + } + + public function resumeSession ($session) { + $query = PartKeepr::getEM()->createQuery("SELECT s FROM PartKeepr\\Session\\Session s WHERE s.sessionid = :session"); + $query->setParameter("session", $session); + $query->execute(); + try { + self::$currentSession = $query->getSingleResult(); + return self::$currentSession; + } catch (\Doctrine\ORM\NonUniqueResultException $e) { + throw new \Exception("Fatal error: Multiple sessions with id $session found."); + } catch (\Doctrine\ORM\NoResultException $e) { + throw new SessionNotFoundException($session); + } + + } +} +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Setup/AbstractSetup.php b/src/backend/PartKeepr/Setup/AbstractSetup.php @@ -0,0 +1,44 @@ +<?php +namespace PartKeepr\Setup; + +use Doctrine\ORM\EntityManager; + +/** + * Represents a basic setup step + */ +abstract class AbstractSetup { + private $console; + + /** + * Represents the Doctrine Entity Manager + * @var Doctrine\ORM\EntityManager + */ + protected $entityManager; + + /** + * Represents all messages which are logged during setup + * @var array + */ + private $messages = array(); + + /** + * Constructs the setup step. + * @param EntityManager $em The entity manager + */ + public function __construct (EntityManager $em) { + $this->entityManager = $em; + } + + abstract public function run (); + + public function setConsole ($console) { + $this->console = $console; + } + + public function logMessage ($message) { + if ($this->console) { + echo "- ".$message."\n"; + } + $this->messages[] = $message; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Setup/ConfigFileSetup.php b/src/backend/PartKeepr/Setup/ConfigFileSetup.php @@ -0,0 +1,65 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\Util\Configuration, + PartKeepr\PartKeepr, + PartKeepr\Util\SerializableException; + +/** + * Creates or returns a new config file + */ +class ConfigFileSetup extends AbstractSetup { + + /** + * (non-PHPdoc) + * @see PartKeepr\Setup.AbstractSetup::run() + */ + public function run () { + switch ($_REQUEST["mode"]) { + case "save": + $this->saveConfig(); + break; + case "display": + return $this->displayConfig(); + break; + } + + return null; + } + + /** + * Returns the configuration file as string, so that it can be displayed + * during setup. + * + * @param none + * @return array An array, where the "config" key contains the configuration. + */ + private function displayConfig () { + return array("config" => Configuration::dumpConfig()); + } + + /** + * Saves the configuration file. + * + * @throws SerializableException An exception which describes what has been going wrong + */ + private function saveConfig () { + $configFile = PartKeepr::getRootDirectory()."/config.php"; + + if (file_exists($configFile)) { + if (!is_writable($configFile)) { + $message = "The config.php file could not be written, because it already exists and the webserver has "; + $message .= "no write access to it."; + + throw new SerializableException($message, 10000); + } + } else { + if (!is_writable(PartKeepr::getRootDirectory())) { + $message = "The config.php file could not be written, because the webserver has no write access to it."; + + throw new SerializableException($message, 10001); + } + } + file_put_contents($configFile, Configuration::dumpConfig()); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Setup/FootprintSetup.php b/src/backend/PartKeepr/Setup/FootprintSetup.php @@ -0,0 +1,156 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\Footprint\FootprintManager, + PartKeepr\FootprintCategory\FootprintCategoryManager, + PartKeepr\FootprintCategory\FootprintCategory, + PartKeepr\Footprint\Footprint, + PartKeepr\Footprint\FootprintImage, + PartKeepr\Footprint\FootprintAttachment, + PartKeepr\PartKeepr, + PartKeepr\Setup\Setup; + +class FootprintSetup extends AbstractSetup { + /** + * Holds the migrated footprints + * @var array + */ + private static $migratedFootprints = array(); + + const FOOTPRINT_PATH = "../setup-data/footprints/"; + const FOOTPRINT_FILE = "../setup-data/footprints/footprints.yaml"; + + /** + * Creates the root node for the footprints + */ + public function setupRootNode () { + FootprintCategoryManager::getInstance()->ensureRootExists(); + } + + public function run () { + $this->setupRootNode(); + $this->importFootprintData(); + } + + /** + * Returns a footprint by it's partdb id + * @param int $id The footprint id from the old partdb + */ + public static function getFootprintForOldId ($id) { + return FootprintSetup::$migratedFootprints[$id]; + } + + /** + * Creates a node structure for the given path + * + * @param $path array The components of the path + * @param $node Node The parent node + */ + public function addFootprintPath (Array $path, $node) { + if (count($path) == 0) { + return $node; + } + $name = array_shift($path); + + $childNode = null; + + foreach ($node->getChildren() as $child) { + if ($child->getNode()->getName() == $name) { + $childNode = $child; + } + } + + if ($childNode === null) { + $category = new FootprintCategory(); + $category->setParent($node->getNode()->getId()); + $category->setName($name); + $childNode = FootprintCategoryManager::getInstance()->addCategory($category); + } + + return $this->addFootprintPath($path, $childNode); + } + + /** + * Checks if the specified footprint exists + * @param string $name The footprint name + */ + public function footprintExists ($name) { + $dql = "SELECT COUNT(fp) FROM PartKeepr\Footprint\Footprint fp WHERE fp.name = :name"; + $query = $this->entityManager->createQuery($dql); + $query->setParameter("name", $name); + + if ($query->getSingleScalarResult() == 0) { + return false; + } else { + return true; + } + } + + /** + * Imports the footprints + * @throws \Exception + */ + public function importFootprintData () { + $count = 0; + $skipped = 0; + + /* Import pre-defined footprints */ + $data = Setup::loadYAML(self::FOOTPRINT_FILE); + + foreach ($data as $footprintName => $footprintData) { + /* Check if the footprint with the name already exists. If yes, skip the import for the single footprint */ + if ($this->footprintExists($footprintName)) { + $skipped++; + continue; + } + $footprint = new Footprint(); + $footprint->setName($footprintName); + + if (array_key_exists("description", $footprintData)) { + $footprint->setDescription($footprintData["description"]); + } + + if (array_key_exists("category", $footprintData)) { + $footprintCategory = $this->addFootprintPath(explode("/", $footprintData["category"]), FootprintCategoryManager::getInstance()->getRootNode()); + $footprint->setCategory($footprintCategory->getNode()); + } + + if (array_key_exists("image", $footprintData)) { + $footprintImage = new FootprintImage(); + $footprintImage->setFootprint($footprint); + $footprintImage->replace(self::FOOTPRINT_PATH . $footprintData["image"]); + + $footprint->setImage($footprintImage); + } + + if (array_key_exists("attachments", $footprintData) && is_array($footprintData["attachments"])) { + foreach ($footprintData["attachments"] as $attachment) { + if (!is_array($attachment)) { + throw new \Exception("Error: The property 'attachments' of $footprintName is not an array!"); + } + if (array_key_exists("url", $attachment)) { + try { + $footprintAttachment = new FootprintAttachment(); + $footprintAttachment->setFootprint($footprint); + $footprintAttachment->replaceFromURL($attachment["url"]); + if (array_key_exists("description", $attachment)) { + $footprintAttachment->setDescription($attachment["description"]); + } + + $footprint->getAttachments()->add($footprintAttachment); + } catch (\Exception $e) { + //echo "error with url ".$attachment["url"]."\n"; + } + } + + } + } + + $this->entityManager->persist($footprint); + $count++; + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Imported %d footprints, skipped %d because they already existed", $count, $skipped)); + } +} diff --git a/src/backend/PartKeepr/Setup/ManufacturerSetup.php b/src/backend/PartKeepr/Setup/ManufacturerSetup.php @@ -0,0 +1,56 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr, + PartKeepr\Manufacturer\Manufacturer, + PartKeepr\Manufacturer\ManufacturerManager, + PartKeepr\Manufacturer\ManufacturerICLogo, + PartKeepr\Setup\SiPrefixSetup; + +/** + * Sets up the manufacturers + */ +class ManufacturerSetup extends AbstractSetup { + + const MANUFACTURER_PATH = "../setup-data/manufacturers/"; + const MANUFACTURER_FILE = "../setup-data/manufacturers/manufacturers.yaml"; + + public function run () { + $this->setupManufacturers(); + } + + /** + * Sets up the manufacturers using the YAML file. + * @param $yaml string The path to the manufacturers YAML file + */ + public function setupManufacturers () { + $count=0; + $skipped=0; + $data = Setup::loadYAML(self::MANUFACTURER_FILE); + + foreach ($data as $mfgname => $logos) { + try { + ManufacturerManager::getInstance()->getManufacturerByName($mfgname); + $skipped++; + } catch (\Exception $e) { + $manufacturer = new Manufacturer(); + $manufacturer->setName($mfgname); + + $this->entityManager->persist($manufacturer); + + foreach ($logos as $logo) { + $mfglogo = new ManufacturerICLogo(); + $mfglogo->setManufacturer($manufacturer); + $mfglogo->replace(self::MANUFACTURER_PATH . "images/". $logo); + $mfglogo->setOriginalFilename($logo); + + $this->entityManager->persist($mfglogo); + } + $count++; + } + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Imported %d Manufacturers, skipped %d because they already exist", $count, $skipped)); + } +} diff --git a/src/backend/PartKeepr/Setup/Migration/PartDB/DistributorMigration.php b/src/backend/PartKeepr/Setup/Migration/PartDB/DistributorMigration.php @@ -0,0 +1,34 @@ +<?php +namespace PartKeepr\Setup\Migration\PartDB; + +use PartKeepr\PartKeepr, + PartKeepr\Distributor\Distributor, + PartKeepr\Distributor\DistributorManager, + PartKeepr\Setup\AbstractSetup; + +class DistributorMigration extends AbstractSetup { + /** + * Migrates the existing distributors + */ + public function run () { + $count = 0; + $skipped = 0; + $r = mysql_query("SELECT * FROM suppliers"); + while ($supplier = mysql_fetch_assoc($r)) { + $name = PartDBMigration::convertText($supplier["name"]); + try { + $distributor = DistributorManager::getInstance()->getDistributorByName($name); + $skipped++; + } catch (\Exception $e) { + $distributor = new Distributor(); + $distributor->setName($name); + + $this->entityManager->persist($distributor); + $count++; + } + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Migrated %d distributors, skipped %d because they already exist", $count, $skipped)); + } +} diff --git a/src/backend/PartKeepr/Setup/Migration/PartDB/FootprintMigration.php b/src/backend/PartKeepr/Setup/Migration/PartDB/FootprintMigration.php @@ -0,0 +1,43 @@ +<?php +namespace PartKeepr\Setup\Migration\PartDB; + +use PartKeepr\PartKeepr, + PartKeepr\Footprint\Footprint, + PartKeepr\Footprint\FootprintManager, + PartKeepr\FootprintCategory\FootprintCategoryManager, + PartKeepr\Setup\FootprintSetup; + +class FootprintMigration extends FootprintSetup { + /** + * Migrates the existing footprints + */ + public function run () { + $count = 0; + $skipped = 0; + + // Get or create node for the imported footprints + $footprintCategory = FootprintSetup::addFootprintPath(explode("/", "Imported Footprints"), FootprintCategoryManager::getInstance()->getRootNode()); + + $r = mysql_query("SELECT * FROM footprints"); + + while ($sFootprint = mysql_fetch_assoc($r)) { + $name = PartDBMigration::convertText($sFootprint["name"]); + + try { + FootprintManager::getInstance()->getFootprintByName($name); + $skipped++; + } catch (\Exception $e) { + $footprint = new Footprint(); + $footprint->setName($name); + + $footprint->setCategory($footprintCategory->getNode()); + + $this->entityManager->persist($footprint); + $count++; + } + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Migrated %d footprints, skipped %d because they already exist", $count, $skipped)); + } +} diff --git a/src/backend/PartKeepr/Setup/Migration/PartDB/PartCategoryMigration.php b/src/backend/PartKeepr/Setup/Migration/PartDB/PartCategoryMigration.php @@ -0,0 +1,50 @@ +<?php +namespace PartKeepr\Setup\Migration\PartDB; + +use PartKeepr\PartKeepr, + PartKeepr\PartCategory\PartCategory, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Setup\AbstractSetup; + +class PartCategoryMigration extends AbstractSetup { + private $categories = array(); + private static $migratedCategories = array(); + /** + * Migrates the old categories + */ + public function run () { + $this->addCategoryRecursive(0, array()); + + foreach ($this->categories as $oldid => $category) { + $newcategory = PartCategoryManager::getInstance()->createCategoryTreeByArray($category); + + self::$migratedCategories[$oldid] = $newcategory; + } + + } + + /** + * Creates the category tree, recursive + * @param array $aCategories the categories + * @param id $currentId The current ID to migrate + * @param Node $parent The parent node + */ + private function addCategoryRecursive ($parentId, $parents) { + $r = mysql_query("SELECT * FROM categories WHERE parentnode = ".intval($parentId)); + + while ($category = mysql_fetch_array($r)) { + $aCopy = $parents; + $aCopy[] = $category["name"]; + + $this->categories[$category["id"]] = $aCopy; + $this->addCategoryRecursive($category["id"], $aCopy); + } + } + + public static function getMigratedCategory ($id) { + if (!array_key_exists($id, self::$migratedCategories)) { + print_r(self::$migratedCategories); + } + return self::$migratedCategories[$id]; + } +} diff --git a/src/backend/PartKeepr/Setup/Migration/PartDB/PartDBMigration.php b/src/backend/PartKeepr/Setup/Migration/PartDB/PartDBMigration.php @@ -0,0 +1,71 @@ +<?php +namespace PartKeepr\Setup\Migration\PartDB; + +use PartKeepr\PartKeepr, + PartKeepr\Util\Configuration as PartKeeprConfiguration; + +class PartDBMigration { + /** + * Specifies if setup runs in console mode. + * @var boolean + */ + private $console = false; + + /** + * Runs the setup with all steps + */ + public function run () { + $this->runStep("all"); + } + + /** + * Sets console mode. + * + * In this mode, messages are directly written to the console. + */ + public function setConsole () { + $this->console = true; + } + + /** + * Runs a specific setup step, or all steps. + * @param string $step + * @throws \Exception + */ + public function runStep ($step) { + $entityManager = PartKeepr::getEM(); + + $aSteps = array( + "distributor" => new DistributorMigration($entityManager), + "footprint" => new FootprintMigration($entityManager), + "partcategory" => new PartCategoryMigration($entityManager), + "storagelocation" => new StorageLocationMigration($entityManager), + "part" => new PartMigration($entityManager) + ); + + if ($step == "all") { + foreach ($aSteps as $step) { + $step->setConsole($this->console); + $step->run(); + } + } else { + if (array_key_exists($step, $aSteps)) { + $aSteps[$step]->run(); + } else { + throw new \Exception(sprintf("Migration step %s doesn't exist", $step)); + } + } + } + + /** + * Converts strange escpaes in the database to "regular" text. + * @param string $string The string to convert + * @return string The converted string + */ + public static function convertText ($string) { + $string = stripslashes($string); + $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8'); + $string = str_replace("&#937;", "Ω", $string); + return $string; + } +} diff --git a/src/backend/PartKeepr/Setup/Migration/PartDB/PartMigration.php b/src/backend/PartKeepr/Setup/Migration/PartDB/PartMigration.php @@ -0,0 +1,131 @@ +<?php +namespace PartKeepr\Setup\Migration\PartDB; + +use PartKeepr\PartKeepr, + PartKeepr\Part\Part, + PartKeepr\Part\PartAttachment, + PartKeepr\Part\PartDistributor, + PartKeepr\Part\PartManager, + PartKeepr\Stock\StockEntry, + PartKeepr\Distributor\DistributorManager, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Footprint\FootprintManager, + PartKeepr\PartUnit\PartUnitManager, + PartKeepr\StorageLocation\StorageLocationManager, + PartKeepr\Setup\AbstractSetup; + +class PartMigration extends AbstractSetup { + /** + * Migrates the existing distributors + */ + public function run () { + $count = 0; + $skipped = 0; + $fc = 0; + + $r = mysql_query("SELECT * FROM parts"); + + while ($part = mysql_fetch_assoc($r)) { + $name = PartDBMigration::convertText($part["name"]); + + $oPart = new Part(); + $oPart->setName($name); + $oPart->setComment(PartDBMigration::convertText($part["comment"])); + + $oPart->setFootprint($this->getFootprintForPart($part["id"])); + $oPart->setReviewFlag(true); + $category = PartCategoryMigration::getMigratedCategory($part["id_category"]); + + if ($category === null) { + PartCategoryManager::getInstance()->getRootNode()->getNode(); + } else { + $oPart->setCategory($category); + } + + $oPart->setStorageLocation($this->getStorageLocationForPart($part["id"])); + $oPart->setMinStockLevel($part["mininstock"]); + $oPart->setPartUnit(PartUnitManager::getInstance()->getDefaultPartUnit()); + + $partDistributor = new PartDistributor(); + $partDistributor->setPart($oPart); + $partDistributor->setDistributor($this->getDistributorForPart($part["id"])); + $partDistributor->setOrderNumber($part["supplierpartnr"]); + $oPart->getDistributors()->add($partDistributor); + + + /* Add existing datasheets */ + $datasheetQuery = "SELECT datasheeturl FROM datasheets WHERE part_id = ".$part["id"]; + $r3 = mysql_query($datasheetQuery); + while ($res = mysql_fetch_assoc($r3)) { + try { + $attachment = new PartAttachment(); + $attachment->setPart($oPart); + $attachment->replaceFromURL($res["datasheeturl"]); + $attachment->setDescription(PartKeepr::i18n("Datasheet")); + $oPart->getAttachments()->add($attachment); + } catch (\Exception $e) { + Setup::progress(" - error with url ".$res["datasheeturl"].". Maybe the datasheet was not found."); + Setup::progress(" - The exception error was: ".$e->getMessage()); + } + } + + PartKeepr::getEM()->persist($oPart); + + $oStock = new StockEntry($oPart, $part["instock"]); + + $priceQuery = "SELECT AVG(preis) AS preis FROM preise WHERE part_id = ".$part["id"]; + + $r2 = mysql_query($priceQuery); + $res = mysql_fetch_assoc($r2); + + if ($res) { + if ($res["preis"] !== null) { + $oStock->setPrice(floatval($res["preis"])); + } + } + + PartKeepr::getEM()->persist($oStock); + + $fc++; + + // Flush every STEP_SIZE parts + if ($fc>PartMigration::STEP_SIZE) { + PartKeepr::getEM()->flush(); + $fc=0; + } + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Migrated %d parts, skipped %d because they already exist", $count, $skipped)); + } + + private function getFootprintForPart ($oldid) { + $r = mysql_query("SELECT footprints.name FROM footprints, parts WHERE footprints.id = parts.id_footprint AND parts.id = ".intval($oldid)); + + $data = mysql_fetch_assoc($r); + + return FootprintManager::getInstance()->getFootprintByName(PartDBMigration::convertText($data["name"])); + } + + private function getStorageLocationForPart ($oldid) { + $r = mysql_query("SELECT storeloc.name FROM storeloc, parts WHERE storeloc.id = parts.id_storeloc AND parts.id = ".intval($oldid)); + + $data = mysql_fetch_assoc($r); + + return StorageLocationManager::getInstance()->getStorageLocationByName(PartDBMigration::convertText($data["name"])); + } + + private function getDistributorForPart ($oldid) { + $r = mysql_query("SELECT suppliers.name FROM suppliers, parts WHERE suppliers.id = parts.id_supplier AND parts.id = ".intval($oldid)); + + $data = mysql_fetch_assoc($r); + + return DistributorManager::getInstance()->getDistributorByName(PartDBMigration::convertText($data["name"])); + } + + /** + * Defines the size of the records which are held in memory unless we flush to the DB. + * @var int + */ + const STEP_SIZE = 100; +} diff --git a/src/backend/PartKeepr/Setup/Migration/PartDB/StorageLocationMigration.php b/src/backend/PartKeepr/Setup/Migration/PartDB/StorageLocationMigration.php @@ -0,0 +1,51 @@ +<?php +namespace PartKeepr\Setup\Migration\PartDB; + +use PartKeepr\PartKeepr, + PartKeepr\StorageLocation\StorageLocation, + PartKeepr\StorageLocation\StorageLocationManager, + PartKeepr\Setup\AbstractSetup; + +class StorageLocationMigration extends AbstractSetup { + /** + * Holds the migrated storage locations + * @var array + */ + private static $migratedStorageLocations = array(); + + /** + * Migrates the storage locations + */ + public function run () { + $count = 0; + $skipped = 0; + + $r = mysql_query("SELECT * FROM storeloc"); + + while ($store = mysql_fetch_assoc($r)) { + $name = PartDBMigration::convertText($store["name"]); + try { + $storageLocation = StorageLocationManager::getInstance()->getStorageLocationByName($name); + $skipped++; + } catch (\Exception $e) { + $oStorageLocation = new StorageLocation(); + $oStorageLocation->setName($name); + + $this->entityManager->persist($oStorageLocation); + $count++; + } + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Migrated %d storage locations, skipped %d because they already exist", $count, $skipped)); + + } + + /** + * Returns the storage location by id + * @param int $id + */ + public static function getMigratedStorageLocation ($id) { + return StorageLocationSetup::$migratedStorageLocations[$id]; + } +} diff --git a/src/backend/PartKeepr/Setup/MiscSettingsSetup.php b/src/backend/PartKeepr/Setup/MiscSettingsSetup.php @@ -0,0 +1,69 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\CronLogger\CronLoggerManager, + PartKeepr\PartKeepr; + +/** + * Sets up misc stuff, which doesn't fit into other steps + */ +class MiscSettingsSetup extends AbstractSetup { + public function run () { + $this->markCronjobsAsRun(); + $this->clearAPCCache(); + $this->regenerateProxies(); + } + + /** + * Marks the cronjobs as run, so that the user doesn't get an error during the first day. + * + * This is necessary because if the user sets up the system and enters the cronjobs, there is a chance + * that no cronjob has been ran when he logs in the first time and thus gets confused. + */ + public function markCronjobsAsRun () { + foreach (PartKeepr::getRequiredCronjobs() as $cronjob) { + CronLoggerManager::getInstance()->markCronRun($cronjob); + } + } + + /** + * Clears the APC cache to push out old entries + */ + public function clearAPCCache () { + if (function_exists("apc_clear_cache")) { + apc_clear_cache(); + apc_clear_cache("user"); + } + } + + /** + * Re-generates all proxies. This is analog to doctrine orm:generate-proxies + * + * @throws \InvalidArgumentException + */ + public function regenerateProxies () { + $em = $this->entityManager; + + $metadatas = $em->getMetadataFactory()->getAllMetadata(); + $destPath = $em->getConfiguration()->getProxyDir(); + + if ( ! is_dir($destPath)) { + mkdir($destPath, 0777, true); + } + + $destPath = realpath($destPath); + + if ( ! file_exists($destPath)) { + throw new \InvalidArgumentException( + sprintf("Proxies destination directory '<info>%s</info>' does not exist.", $em->getConfiguration()->getProxyDir()) + ); + } else if ( ! is_writable($destPath)) { + throw new \InvalidArgumentException( + sprintf("Proxies destination directory '<info>%s</info>' does not have write permissions.", $destPath) + ); + } + + $em->getProxyFactory()->generateProxyClasses($metadatas, $destPath); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Setup/PartCategorySetup.php b/src/backend/PartKeepr/Setup/PartCategorySetup.php @@ -0,0 +1,28 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\PartCategory\PartCategory; + +class PartCategorySetup extends AbstractSetup { + /** + * Sets up the root category node + */ + public function setupRootCategory () { + PartCategoryManager::getInstance()->ensureRootExists(); + } + + public function updateCategoryPathCache () { + PartCategoryManager::getInstance()->updateCategoryPaths( + PartCategoryManager::getInstance()->getRootNode() + ); + + PartKeepr::getEM()->flush(); + } + + public function run () { + $this->setupRootCategory(); + $this->updateCategoryPathCache(); + } +} diff --git a/src/backend/PartKeepr/Setup/PartUnitSetup.php b/src/backend/PartKeepr/Setup/PartUnitSetup.php @@ -0,0 +1,36 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr, + PartKeepr\Part\PartUnit; + +class PartUnitSetup extends AbstractSetup { + /** + * Holds the default unit + * @var object + */ + private static $defaultUnit; + + /** + * Sets up the default part unit if none exists + */ + public function run () { + $dql = "SELECT COUNT(p) FROM PartKeepr\Part\PartUnit p WHERE p.is_default = :default"; + $query = $this->entityManager->createQuery($dql); + $query->setParameter("default", true); + + if ($query->getSingleScalarResult() == 0) { + $partUnit = new PartUnit(); + $partUnit->setName(PartKeepr::i18n("Pieces")); + $partUnit->setShortName(PartKeepr::i18n("pcs")); + $partUnit->setDefault(true); + + $this->entityManager->persist($partUnit); + $this->entityManager->flush(); + + $this->logMessage("Added default part unit"); + } else { + $this->logMessage("Skipped adding default part unit, because a default part unit already exists"); + } + } +} diff --git a/src/backend/PartKeepr/Setup/SchemaSetup.php b/src/backend/PartKeepr/Setup/SchemaSetup.php @@ -0,0 +1,34 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr; +/** + * Updates (or creates) the database schema + */ +class SchemaSetup extends AbstractSetup { + public function run () { + $tool = new \Doctrine\ORM\Tools\SchemaTool($this->entityManager); + $classes = PartKeepr::getClassMetaData(); + $tool->updateSchema($classes, true); + $this->logMessage("Database Schema created/updated"); + } + + /** + * Checks if the specified database has UTF-8 encoding + * @param $connection The DBAL connection + * @param string $dbname + */ + public static function mysqlHasUTF8Encoding ($connection, $dbname) { + $statement = $connection->prepare("SELECT default_character_set_name FROM information_schema.SCHEMATA S WHERE schema_name = :schema"); + $statement->bindValue("schema", $dbname); + $statement->execute(); + + $encoding = $statement->fetchColumn(0); + + if ($encoding != "utf8") { + return false; + } else { + return true; + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Setup/Setup.php b/src/backend/PartKeepr/Setup/Setup.php @@ -0,0 +1,176 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr, + PartKeepr\Util\Configuration as PartKeeprConfiguration; + +class Setup { + /** + * Specifies if setup runs in console mode. + * @var boolean + */ + private $console = false; + + /** + * Defines if the setup runs in verbose mode. + * @var boolean + */ + private static $verbose = false; + + /** + * Runs the migration with all steps + */ + public function run () { + $this->runStep("all"); + } + + /** + * Sets console mode. + * + * In this mode, messages are directly written to the console. + */ + public function setConsole () { + $this->console = true; + } + + /** + * Runs a specific setup step, or all steps. + * + * @param string $step The step to execute + * @throws \Exception + */ + public function runStep ($step) { + $entityManager = PartKeepr::getEM(); + + $aSteps = array( + "schema" => new SchemaSetup($entityManager), + "adminuser" => new UserSetup($entityManager), + "partunit" => new PartUnitSetup($entityManager), + "footprint" => new FootprintSetup($entityManager), + "partcategory" => new PartCategorySetup($entityManager), + "siprefix" => new SiPrefixSetup($entityManager), + "unit" => new UnitSetup($entityManager), + "manufacturer" => new ManufacturerSetup($entityManager), + "miscsettings" => new MiscSettingsSetup($entityManager) + ); + + $aActions = array( + "configfile" => new ConfigFileSetup($entityManager) + ); + if ($step == "all") { + foreach ($aSteps as $step) { + $step->setConsole($this->console); + $step->run(); + } + } else { + if (array_key_exists($step, $aSteps)) { + return $aSteps[$step]->run(); + } + + if (array_key_exists($step, $aActions)) { + return $aActions[$step]->run(); + } + + throw new \Exception(sprintf("Setup step %s doesn't exist", $step)); + } + } + + /** + * Tests for APC. Throws an exception if APC is missing or not active. + * @throws \Exception + */ + public function testAPC () { + if (!extension_loaded("apc")) { + throw new \Exception(PartKeepr::i18n("The extension 'apc' is not loaded. Make sure that it is installed (see http://php.net/manual/en/apc.installation.php) and that it is enabled (set apc.enabled=1 in your php.ini).")); + } + } + + /** + * Tests for suitable memory_limit settings + * @todo stub + */ + public function testMemoryLimit () { + //echo ini_get("memory_limit"); + } + + /** + * Sets the verbose flag + * @param boolean $verbose True if verbose output is wanted, false otherwise + */ + public static function setVerbose ($verbose) { + Setup::$verbose = $verbose; + } + + /** + * Outputs a progress message. + * + * @param string $string The string to output + * @param boolean $verbose True if the string should only be printed if verbosity is turned on + */ + public static function progress ($string, $verbose = false) { + if (!$verbose || ($verbose && Setup::$verbose)) { + echo $string."\n"; + } + + } + + /** + * Loads the given YAML file. Due to an API brach between Doctrine 2.0.5 and Doctrine 2.0.6, + * we need to work it around. + * @param string $file The path of the file to load + * @return array The parsed YAML file + */ + public static function loadYAML ($file) { + return \Symfony\Component\Yaml\Yaml::parse($file); + } + + /** + * Sets the database configuration array from $_REQUEST + */ + public static function setDatabaseConfigurationFromRequest () { + if (isset($_REQUEST["dbname"])) { + PartKeeprConfiguration::setOption("partkeepr.database.dbname", $_REQUEST["dbname"]); + } + + if (isset($_REQUEST["user"])) { + PartKeeprConfiguration::setOption("partkeepr.database.username", $_REQUEST["user"]); + } + if (isset($_REQUEST["password"])) { + PartKeeprConfiguration::setOption("partkeepr.database.password", $_REQUEST["password"]); + } + if (isset($_REQUEST["host"])) { + PartKeeprConfiguration::setOption("partkeepr.database.host", $_REQUEST["host"]); + } + + if (isset($_REQUEST['port'])) { + PartKeeprConfiguration::setOption("partkeepr.database.port", $_REQUEST["port"]); + } + + switch ($_REQUEST["driver"]) { + case "mysql": + PartKeeprConfiguration::setOption("partkeepr.database.driver","pdo_mysql"); + break; + case "pgsql": + PartKeeprConfiguration::setOption("partkeepr.database.driver","pdo_pgsql"); + break; + default: + throw new \Exception(sprintf("Invalid driver %s specified.", $_REQUEST["driver"])); + break; + } + } + + /** + * Runs some checks for the CLI setup + */ + public function runCLIChecks () { + + if (PartKeeprConfiguration::getOption("partkeepr.database.driver") == "pdo_mysql") { + $dbname = PartKeeprConfiguration::getOption("partkeepr.database.dbname"); + if (!SchemaSetup::mysqlHasUTF8Encoding(PartKeepr::getEM()->getConnection(), $dbname )) { + echo "Error: The database $dbname hasn't got the UTF-8 encoding. You need to set the database encoding to UTF-8. Aborting.\n"; + die; + } + } + + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Setup/SiPrefixSetup.php b/src/backend/PartKeepr/Setup/SiPrefixSetup.php @@ -0,0 +1,47 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr, + PartKeepr\SiPrefix\SiPrefix, + PartKeepr\SiPrefix\SiPrefixManager; + +class SiPrefixSetup extends AbstractSetup { + + const SIPREFIX_DATA_FILE = "../setup-data/siprefixes.yaml"; + + /** + * Stores the migrated si prefixes + * @var array + */ + private static $siPrefixes = array(); + + public function run () { + $this->setupSiPrefixes(); + } + + /** + * Sets up the SI prefixes + */ + public function setupSiPrefixes () { + $count = 0; + $skipped = 0; + + $data = Setup::loadYAML(self::SIPREFIX_DATA_FILE); + + foreach ($data as $prefixName => $prefixData) { + if (!SiPrefixManager::getInstance()->siPrefixExists($prefixName)) { + $prefix = new SiPrefix(); + $prefix->setPrefix($prefixName); + $prefix->setPower($prefixData["power"]); + $prefix->setSymbol($prefixData["symbol"]); + $this->entityManager->persist($prefix); + $count++; + } else { + $skipped++; + } + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Imported %d Si Prefixes, skipped %d", $count, $skipped)); + } +} diff --git a/src/backend/PartKeepr/Setup/UnitSetup.php b/src/backend/PartKeepr/Setup/UnitSetup.php @@ -0,0 +1,62 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\PartKeepr, + PartKeepr\Unit\Unit, + PartKeepr\SiPrefix\SiPrefixManager, + PartKeepr\Unit\UnitManager, + PartKeepr\Setup\SiPrefixSetup; + +class UnitSetup extends AbstractSetup { + + const UNIT_DATA_FILE = "../setup-data/units.yaml"; + + + public function run () { + $this->setupUnits(); + } + /** + * Sets up the default units + * @throws \Exception + */ + public function setupUnits () { + $count = 0; + $skipped = 0; + $data = Setup::loadYAML(self::UNIT_DATA_FILE); + + $aUnits = array(); + + foreach ($data as $unitName => $unitData) { + if (UnitManager::getInstance()->unitExists($unitName)) { + $skipped++; + continue; + } + $unit = new Unit(); + $unit->setName($unitName); + $unit->setSymbol($unitData["symbol"]); + + if (array_key_exists("prefixes", $unitData)) { + if (!is_array($unitData["prefixes"])) { + throw new \Exception($unitName." doesn't contain a prefix list, or the prefix list is not an array."); + } + + foreach ($unitData["prefixes"] as $prefix) { + + $siPrefix = SiPrefixManager::getInstance()->getSiPrefixBySymbol($prefix); + if ($siPrefix === false) { + throw new \Exception("Unable to find prefix ".$prefix); + } + $unit->getPrefixes()->add($siPrefix); + } + } + + PartKeepr::getEM()->persist($unit); + $count++; + } + + $this->entityManager->flush(); + $this->logMessage(sprintf("Imported %d Units, skipped %d because they already exist", $count, $skipped)); + } + + +} diff --git a/src/backend/PartKeepr/Setup/UserSetup.php b/src/backend/PartKeepr/Setup/UserSetup.php @@ -0,0 +1,31 @@ +<?php +namespace PartKeepr\Setup; + +use PartKeepr\User\User; + +/** + * Creates a new admin user, but only if no admin user exists. + */ +class UserSetup extends AbstractSetup { + public function run () { + $dql = "SELECT COUNT(u) FROM PartKeepr\User\User u WHERE u.username = :username OR u.admin = :admin"; + $query = $this->entityManager->createQuery($dql); + $query->setParameter("username", "admin"); + $query->setParameter("admin", true); + + if ($query->getSingleScalarResult() == 0) { + $user = new User(); + $user->setUsername("admin"); + $user->setPassword("admin"); + $user->setAdmin(true); + + $this->entityManager->persist($user); + $this->entityManager->flush(); + + $this->logMessage("Admin User created"); + } else { + $this->logMessage( "Skipped admin user creation, because an user named 'admin'". + "or another user with an admin flag already exists"); + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/SiPrefix/SiPrefix.php b/src/backend/PartKeepr/SiPrefix/SiPrefix.php @@ -0,0 +1,91 @@ +<?php +namespace PartKeepr\SiPrefix; + +use PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr, + PartKeepr\Util\Exceptions\OutOfRangeException; + + +/** @Entity **/ +class SiPrefix extends BaseEntity { + /** + * The prefix of the Si-Prefix (e.g. yotta, deca, deci, centi) + * @Column(type="string") + * @var string + */ + private $prefix; + + /** + * The symbol of the Si-Prefix (e.g. m, M, G) + * @Column(type="string",length=2) + * @var string + */ + private $symbol; + + /** + * The power of the Si-Prefix (e.g. milli = 10^-3) + * @Column(type="integer") + * @var int + */ + private $power; + + /** + * Sets the prefix name. + * @param string $prefix + */ + public function setPrefix ($prefix) { + $this->prefix = $prefix; + } + + /** + * Returns the prefix name + * @return string The prefix name + */ + public function getPrefix () { + return $this->prefix; + } + + /** + * Sets the symbol for the prefix + * @param string $symbol The symbol + */ + public function setSymbol ($symbol) { + $this->symbol = $symbol; + } + + /** + * Returns the symbol for the prefix + * @return string The symbol + */ + public function getSymbol () { + return $this->symbol; + } + + /** + * Sets the power in a 10^n power (n=power) + * @param int $power The 10^power + */ + public function setPower ($power) { + $this->power = $power; + } + + /** + * Returns the power (10^n) + * @return int The power + */ + public function getPower () { + return $this->power; + } + + /** + * Serializes the object into an array format. + * @return array the object in serialized format. + */ + public function serialize () { + return array( + "id" => $this->getId(), + "symbol" => $this->getSymbol(), + "prefix" => $this->getPrefix(), + "power" => $this->getPower()); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/SiPrefix/SiPrefixManager.php b/src/backend/PartKeepr/SiPrefix/SiPrefixManager.php @@ -0,0 +1,42 @@ +<?php +namespace PartKeepr\SiPrefix; + +use PartKeepr\Util\Singleton, + PartKeepr\PartKeepr; + +class SiPrefixManager extends Singleton { + public $siPrefixSymbolCache = array(); + + public function getSiPrefixBySymbol ($symbol) { + if (!is_array($this->siPrefixSymbolCache) || count($this->siPrefixSymbolCache) == 0) { + $this->createSiPrefixSymbolCache(); + } + + foreach ($this->siPrefixSymbolCache as $entry) { + if ($entry->getSymbol() == $symbol) { + return $entry; + } + } + + throw new \Exception(sprintf("Symbol '%s' not found", $symbol)); + } + + private function createSiPrefixSymbolCache () { + $dql = "SELECT sip FROM PartKeepr\SiPrefix\SiPrefix sip"; + $query = PartKeepr::getEM()->createQuery($dql); + + $this->siPrefixSymbolCache = $query->getResult(); + } + + public function siPrefixExists ($prefix) { + $dql = "SELECT COUNT(sip) FROM PartKeepr\SiPrefix\SiPrefix sip WHERE sip.prefix = :prefix"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("prefix", $prefix); + + if ($query->getSingleScalarResult() == 0) { + return false; + } else { + return true; + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/SiPrefix/SiPrefixService.php b/src/backend/PartKeepr/SiPrefix/SiPrefixService.php @@ -0,0 +1,27 @@ +<?php +namespace PartKeepr\SiPrefix; + +use PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Session\SessionManager; + +class SiPrefixService extends Service implements RestfulService { + public function get () { + $query = PartKeepr::getEM()->createQuery("SELECT si.id, si.prefix, si.symbol, si.power FROM PartKeepr\SiPrefix\SiPrefix si"); + + return array("data" => $query->getArrayResult()); + } + + public function create () { + throw new \Exception("Not yet implemented"); + } + + public function update () { + throw new \Exception("Not yet implemented"); + } + + public function destroy () { + throw new \Exception("Not yet implemented"); + } +} diff --git a/src/backend/PartKeepr/Statistic/StatisticService.php b/src/backend/PartKeepr/Statistic/StatisticService.php @@ -0,0 +1,148 @@ +<?php +namespace PartKeepr\Statistic; + +use PartKeepr\Part\PartUnit, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Part\PartManager, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\PartUnit\PartUnitManager; + +class StatisticService extends Service { + public function getCurrentStats () { + + $aData = array(); + $aData["partCount"] = PartManager::getInstance()->getPartCount(); + $aData["categoryCount"] = PartCategoryManager::getInstance()->getCategoryCount(); + $aData["totalPrice"] = PartManager::getInstance()->getTotalPrice(); + $aData["averagePrice"] = PartManager::getInstance()->getAveragePrice(); + $aData["partsWithPrice"] = PartManager::getInstance()->getPartCount(true); + $aData["partsWithoutPrice"] = $aData["partCount"] - $aData["partsWithPrice"]; + + $result = PartUnitManager::getInstance()->getUnitCounts(); + + $aUnits = array(); + + foreach ($result as $row) { + $aUnits[] = array( + "name" => PartUnit::loadById($row["puid"])->getName(), + "stockLevel" => $row["stockLevel"]); + } + + $aData["units"] = $aUnits; + + return $aData; + } + + /** + * Returns the range of all recorded statistic snapshots. + */ + public function getStatisticRange () { + $dql = "SELECT MIN(sts.dateTime), MAX(sts.dateTime) FROM PartKeepr\Statistic\StatisticSnapshot sts"; + $query = PartKeepr::getEM()->createQuery($dql); + + $data = $query->getArrayResult(); + + return array("data" => array("start" => $data[0][1], "end" => $data[0][2])); + + } + /** + * Returns sampled statistics from the database. + * + * This call takes a start and an end time, and calculates a set of statistics + * for each interval. + * + * The sampleSize, which has a default of 50, specifies how many single statistic + * points in the given date interval will be returned. + * + * This function interpolates the statistics if there are not enough statistic samples available. + */ + public function getSampledStatistics () { + $fooStart = microtime(true); + + $this->requireParameter("startDateTime"); + $this->requireParameter("endDateTime"); + + + $start = \DateTime::createFromFormat("Y-m-d H:i:s", $this->getParameter("startDateTime")); + $end = \DateTime::createFromFormat("Y-m-d H:i:s", $this->getParameter("endDateTime")); + + if ($start->getTimestamp() > $end->getTimestamp()) { + // Swap both times + list($start, $end) = array($end, $start); + } + + if ($this->hasParameter("sampleSize")) { + $sampleSize = $this->getParameter("sampleSize"); + } else { + $sampleSize = 25; + } + + $intervalSize = intval(($end->getTimestamp() - $start->getTimestamp()) / $sampleSize); + + $queryStartTime = clone $start; + $queryEndTime = clone $start; + $queryEndTime->add(new \DateInterval("PT".$intervalSize."S")); + + $partUnitQuery = "SELECT pu FROM PartKeepr\Part\PartUnit pu"; + $query = PartKeepr::getEM()->createQuery($partUnitQuery); + + $aPartUnits = $query->getResult(); + + $aRecords = array(); + + $dql = "SELECT AVG(sts.parts) AS parts, AVG(sts.categories) AS categories FROM PartKeepr\Statistic\StatisticSnapshot sts WHERE sts.dateTime >= :start AND sts.dateTime <= :end"; + $mainQuery = PartKeepr::getEM()->createQuery($dql); + + $dql = "SELECT AVG(stsu.stockLevel) AS stockLevel FROM PartKeepr\Statistic\StatisticSnapshotUnit stsu JOIN stsu.statisticSnapshot sts WHERE sts.dateTime >= :start AND sts.dateTime <= :end AND stsu.partUnit = :partUnit"; + $subQuery = PartKeepr::getEM()->createQuery($dql); + + for ($i=0;$i<$sampleSize;$i++) { + + + $mainQuery->setParameter("start", $queryStartTime); + $mainQuery->setParameter("end", $queryEndTime); + + $result = $mainQuery->getResult(); + + $record = $result[0]; + + if ($record["parts"] !== null) { + $record["parts"] = floatval($record["parts"]); + } + + if ($record["categories"] !== null) { + $record["categories"] = floatval($record["categories"]); + } + + foreach ($aPartUnits as $partUnit) { + $subQuery->setParameter("start", $queryStartTime); + $subQuery->setParameter("end", $queryEndTime); + $subQuery->setParameter("partUnit", $partUnit); + + $aResult = $subQuery->getResult(); + + if ($aResult[0]["stockLevel"] !== null) { + $record["units"][$partUnit->getName()] = floatval($aResult[0]["stockLevel"]); + } else { + $record["units"][$partUnit->getName()] = null; + } + + } + + $record["start"] = $queryStartTime->format("Y-m-d H:i:s"); + + if ($record["parts"] !== null) { + $aRecords[] = $record; + } + + + $queryStartTime->add(new \DateInterval("PT".$intervalSize."S")); + $queryEndTime->add(new \DateInterval("PT".$intervalSize."S")); + } + + + return array("status" => "ok", "data" => $aRecords); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Statistic/StatisticSnapshot.php b/src/backend/PartKeepr/Statistic/StatisticSnapshot.php @@ -0,0 +1,109 @@ +<?php +namespace PartKeepr\Statistic; + +use PartKeepr\PartKeepr; + +/** @Entity **/ +class StatisticSnapshot { + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + * @var integer + */ + private $id; + + /** + * Defines the date when this snapshot has been taken + * @Column(type="datetime") + * @var DateTime + */ + private $dateTime; + + /** + * Defines the amount of different parts in the database + * @Column(type="integer") + * @var int + */ + private $parts; + + /** + * Defines the amount of categories + * @Column(type="integer") + * @var int + */ + private $categories; + + /** + * Holds all defined units in the database + * @OneToMany(targetEntity="PartKeepr\Statistic\StatisticSnapshotUnit",mappedBy="statisticSnapshot",cascade={"persist", "remove"}) + */ + private $units; + + /** + * Creates a new statistic snapshot + */ + public function __construct () { + $this->units = new \Doctrine\Common\Collections\ArrayCollection(); + $this->setDateTime(new \DateTime()); + } + + /** + * Sets the date+time for the snapshot + * @param \DateTime $dateTime The date+time for the snapshot + */ + public function setDateTime (\DateTime $dateTime) { + $this->dateTime = $dateTime; + } + + /** + * Returns the date+time for the snapshot + * @return DateTime The date+time for the snapshot + */ + public function getDateTime () { + return $this->dateTime; + } + + /** + * Sets the amount of overall parts for the snapshot + * @param int $parts The amount of parts + */ + public function setParts ($parts) { + $this->parts = $parts; + } + + /** + * Returns the amount of overall parts for the snapshot + * @return int The amount of parts + */ + public function getParts () { + return $this->parts; + } + + /** + * Sets the amount of categories for the snapshot + * @param int $categories The amount of categories + */ + public function setCategories ($categories) { + $this->categories = $categories; + } + + /** + * Returns the amount of categories + * @return int The amount of categories + */ + public function getCategories () { + return $this->categories; + } + + /** + * Returns the ID of this snapshot + * @return int The ID of this snapshot + */ + public function getId () { + return $this->id; + } + + public function getUnits () { + return $this->units; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Statistic/StatisticSnapshotManager.php b/src/backend/PartKeepr/Statistic/StatisticSnapshotManager.php @@ -0,0 +1,38 @@ +<?php +namespace PartKeepr\Statistic; + +use PartKeepr\Util\Singleton, + PartKeepr\Part\PartUnit, + PartKeepr\Part\PartManager, + PartKeepr\PartUnit\PartUnitManager, + PartKeepr\PartKeepr, + PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\PartUnit\Exceptions\PartUnitNotFoundException; + +class StatisticSnapshotManager extends Singleton { + public function createSnapshot () { + + $snapshot = new StatisticSnapshot(); + $snapshot->setParts(PartManager::getInstance()->getPartCount()); + $snapshot->setCategories(PartCategoryManager::getInstance()->getCategoryCount()); + + $result = PartUnitManager::getInstance()->getUnitCounts(); + + foreach ($result as $row) { + $snapshotUnit = new StatisticSnapshotUnit(); + $snapshotUnit->setPartUnit(PartUnit::loadById($row["puid"])); + $snapshotUnit->setStatisticSnapshot($snapshot); + + if ($row["stockLevel"] !== null) { + $snapshotUnit->setStockLevel($row["stockLevel"]); + } else { + $snapshotUnit->setStockLevel(0); + } + + $snapshot->getUnits()->add($snapshotUnit); + } + + PartKeepr::getEM()->persist($snapshot); + PartKeepr::getEM()->flush(); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Statistic/StatisticSnapshotUnit.php b/src/backend/PartKeepr/Statistic/StatisticSnapshotUnit.php @@ -0,0 +1,95 @@ +<?php +namespace PartKeepr\Statistic; + +use PartKeepr\Statistic\StatisticSnapshot, + PartKeepr\Part\PartUnit, + PartKeepr\PartKeepr; + + +/** @Entity **/ +class StatisticSnapshotUnit { + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + * @var integer + */ + private $id; + + /** + * @ManyToOne(targetEntity="PartKeepr\Statistic\StatisticSnapshot") + * The statistic snapshot this entity belongs to + * @var StatisticSnapshot + */ + private $statisticSnapshot; + + /** + * @ManyToOne(targetEntity="PartKeepr\Part\PartUnit") + * The statistic snapshot this entity belongs to + * @var StatisticSnapshot + */ + private $partUnit; + + /** + * The stockLevel for the unit + * @Column(type="integer") + * @var int + */ + private $stockLevel; + + /** + * Sets the statistic snapshot this entity belongs to + * @param StatisticSnapshot $snapshot The snapshot + */ + public function setStatisticSnapshot (StatisticSnapshot $snapshot) { + $this->statisticSnapshot = $snapshot; + } + + /** + * Returns the snapshot this entity belongs to + * @return StatisticSnapshot The snapshot + */ + public function getStatisticSnapshot () { + return $this->statisticSnapshot; + } + + /** + * + * Sets the part unit for this entity + * @param PartUnit $unit The part unit + */ + public function setPartUnit (PartUnit $unit) { + $this->partUnit = $unit; + } + + /** + * Returns the part unit for this entity + * @return PartUnit The part unit + */ + public function getPartUnit () { + return $this->partUnit; + } + + /** + * Returns the ID of this statistic snapshot unit + * @return int The ID + */ + public function getId () { + return $this->id; + } + + /** + * Sets the stock level for this unit snapshot + * @param int $stockLevel + */ + public function setStockLevel ($stockLevel) { + $this->stockLevel = $stockLevel; + } + + /** + * Returns the stock level for this unit snapshot + * @return int The stock level + */ + public function getStockLevel () { + return $this->stockLevel; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Stock/StockEntry.php b/src/backend/PartKeepr/Stock/StockEntry.php @@ -0,0 +1,239 @@ +<?php +namespace PartKeepr\Stock; + +use PartKeepr\Part\Part, + PartKeepr\User\User, + PartKeepr\PartKeepr, + PartKeepr\Util\BaseEntity, + PartKeepr\Util\Serializable; + +/** @Entity @HasLifecycleCallbacks **/ +class StockEntry extends BaseEntity implements Serializable { + /** + * @Column(type="integer") + */ + private $stockLevel; + + /** + * @ManyToOne(targetEntity="PartKeepr\Part\Part") + */ + private $part; + + /** + * @ManyToOne(targetEntity="PartKeepr\User\User") + */ + private $user; + + /** + * @Column(type="decimal",precision=13,scale=4,nullable=true) + * @var float + */ + private $price; + + /** + * @Column(type="datetime") + * @var DateTime + */ + private $dateTime; + + /** + * Indicates if the stock level is a correction entry. + * + * @Column(type="boolean") + * @var boolean + */ + private $correction; + + /** + * @Column(type="string",nullable=true) + * @var string + */ + private $comment; + + + /** + * Creates a new stock entry. A stock entry tracks how many parts + * were the stockLevel is the amount of items added/removed, + * by which user and how much the user paid for it (for adding parts only!) + * + * @param Part $part The part which was added/removed + * @param int $stockLevel The stock level. Positive value means added parts, negative values means removed parts. + * @param User $user The user who removed/added parts + */ + public function __construct (Part $part, $stockLevel, User $user = null) { + $this->setPart($part); + $this->setStockLevel($stockLevel); + $this->setUser($user); + $this->setDateTime(new \DateTime()); + $this->setCorrection(false); + } + + + /** + * Sets the date+time + * @param \DateTime $dateTime The date+time + */ + private function setDateTime (\DateTime $dateTime) { + $this->dateTime = $dateTime; + } + + /** + * Returns the date+time when the record was created. + * @return \DateTime The date+time when the record was created + */ + public function getDateTime () { + return $this->dateTime; + } + + /** + * Sets if the stock entry is a correction record. + * @param $bCorrection boolean True if the record is a correction record, false otherwise + */ + public function setCorrection ($bCorrection) { + $this->correction = $bCorrection; + } + + /** + * Returns if the entry is a correction entry. + * @return boolean True if the entry is a correction entry, false otherwise + */ + public function getCorrection () { + return $this->correction; + } + + /** + * Sets the price for the item stored. + * + * Please note that the price is for a single item only, and can be null. + * @param float $price The price to set + */ + public function setPrice ($price) { + $this->price = $price; + } + + /** + * Returns the price for this entry. The price is for a single item only. + * + * @return float The price for this entry. + */ + public function getPrice () { + return $this->price; + } + + /** + * Sets the stock level for this entry. + * + * Negative values means part removal, positive values means part adding. + * @param int $stockLevel The stock level + */ + public function setStockLevel($stockLevel) { + $this->stockLevel = $stockLevel; + } + + /** + * Returns the stock level for this entry. + * @return int The stock level + */ + public function getStockLevel () { + return $this->stockLevel; + } + + /** + * Sets the part assigned to this entry. + * @param Part $part The part to set + */ + public function setPart (Part $part) { + $this->part = $part; + } + + /** + * Returns the part assigned to this entry. + * @return Part $part The part + */ + public function getPart () { + return $this->part; + } + + /** + * Sets the user assigned to this entry. + * @param User $user The user The user to set + */ + public function setUser (User $user = null) { + $this->user = $user; + } + + /** + * Returns the user for this entry + * @return User the user + */ + public function getUser () { + return $this->user; + } + + /** + * If the stock level is negative, we can't have a price. + * @PrePersist + */ + public function checkPrice () { + if ($this->getStockLevel() < 0 && $this->getPrice() !== null) { + $this->setPrice(null); + } + } + + /** + * Updates the stock leve for a part + * @PostPersist + */ + public function postPersist () { + $this->part->updateStockLevel(); + $this->part->updatePrice(); + } + + /** + * Returns if the current stock entry is a removal. + * @return boolean True if the entry is a removal, false otherwise + */ + public function isRemoval () { + if ($this->getStockLevel() < 0) { + return true; + } else { + return false; + } + } + + /** + * Sets a comment + * @param string $comment + */ + public function setComment ($comment) { + $this->comment = $comment; + } + + /** + * Returns the comment + * @return string The comment + */ + public function getComment () { + return $this->comment; + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "id" => $this->getId(), + "part_name" => $this->getPart()->getName(), + "part_id" => $this->getPart()->getId(), + "storageLocation_name" => $this->getPart()->getStorageLocation()->getName(), + "username" => is_object($this->getUser()) ? $this->getUser()->getUsername() : PartKeepr::i18n("Unknown User"), + "user_id" => is_object($this->getUser()) ? $this->getUser()->getId() : null, + "stockLevel" => abs($this->getStockLevel()), + "comment" => $this->getComment(), + "dateTime" => $this->getDateTime()->format("Y-m-d H:i:s"), + "direction" => ($this->getStockLevel() < 0) ? "out" : "in", + "price" => $this->getPrice() + ); + } +} diff --git a/src/backend/PartKeepr/Stock/StockManager.php b/src/backend/PartKeepr/Stock/StockManager.php @@ -0,0 +1,66 @@ +<?php +namespace PartKeepr\Stock; + +use PartKeepr\Manager\AbstractManager, + Doctrine\ORM\QueryBuilder, + PartKeepr\Manager\ManagerFilter, + PartKeepr\PartKeepr; + +class StockManager 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\Stock\StockEntry'; + } + + /** + * 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(); + } + + /** + * Returns the default sort field + * + * @return string The default sort field + */ + public function getDefaultSortField () { + return "dateTime"; + } + + /** + * Applies a custom query to the QueryBuilder + * + * @param QueryBuilder $qb The query builder + * @param ManagerFilter $filter The query filter + */ + protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { + + // Apply special handling for non-direct fields in relations, where the frontend has no idea about. + foreach ($filter->getSorters() as $sorter) { + switch ($sorter->getSortField()) { + case "q.part_name": + $qb->join("q.part", "p"); + $sorter->setSortField("p.name"); + break; + case "q.user_id": + $qb->leftJoin("q.user", "u"); + $sorter->setSortField("u.username"); + break; + case "q.direction": + $sorter->setSortField("q.dateTime"); + break; + case "q.storageLocation_name": + $qb->join("q.part", "p")->join("p.storageLocation", "st"); + $sorter->setSortField("st.name"); + break; + default: + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Stock/StockService.php b/src/backend/PartKeepr/Stock/StockService.php @@ -0,0 +1,93 @@ +<?php +namespace PartKeepr\Stock; + +use PartKeepr\Stock\StockEntry, + PartKeepr\PartKeepr, + PartKeepr\User\User, + PartKeepr\Manager\ManagerFilter, + PartKeepr\Session\SessionManager, + PartKeepr\Service\RestfulService, + PartKeepr\Service\Service; + +class StockService extends Service implements RestfulService { + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + return array("data" => StockManager::getInstance()->getEntity($this->getParameter("id"))->serialize()); + } else { + $parameters = new ManagerFilter($this); + $parameters->setFilterField("name"); + + if ($this->hasParameter("part")) { + $parameters->setFilterCallback(array($this, "filterCallback")); + } + return StockManager::getInstance()->getList($parameters); + } + } + + /** + * If the "part" parameter is set, join the part into the result and filter on that + * @param QueryBuilder The $queryBuilder + */ + public function filterCallback ($queryBuilder) { + $queryBuilder->andWhere("q.part = :part"); + $queryBuilder->setParameter("part", $this->getParameter("part")); + } + + public function create () { + throw new \Exception("Not yet implemented"); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + $this->requireParameter("id"); + + $stockEntry = StockEntry::loadById($this->getParameter("id")); + + if (!SessionManager::getCurrentSession()->getUser()->isAdmin() && + !(SessionManager::getCurrentSession()->getUser() && $stockEntry->getUser() && SessionManager::getCurrentSession()->getUser()->getId() == $stockEntry->getUser()->getId() )) { + throw new \Exception("Permission denied"); + } + + /* It's not allowed to edit a price for a removal */ + if (!$stockEntry->isRemoval()) { + $stockEntry->setPrice(abs($this->getParameter("price"))); + } + + /** + * Only an admin user may correct the in&out stock levels + */ + if (SessionManager::getCurrentSession()->getUser()->isAdmin()) { + if ($this->getParameter("direction") == "out") { + $stockEntry->setStockLevel(-(abs($this->getParameter("stockLevel")))); + } else { + $stockEntry->setStockLevel($this->getParameter("stockLevel")); + } + + } + + if (SessionManager::getCurrentSession()->getUser()->isAdmin()) { + try { + $stockEntry->setUser(User::loadById($this->getParameter("user_id"))); + } catch (\Exception $e) { + $stockEntry->setUser(null); + } + + } + + $stockEntry->setComment($this->getParameter("comment")); + PartKeepr::getEM()->flush(); + + return array("data" => $stockEntry->serialize()); + } + + public function destroy () { + throw new \Exception("Not yet implemented"); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/StorageLocation/Exceptions/StorageLocationNotFoundException.php b/src/backend/PartKeepr/StorageLocation/Exceptions/StorageLocationNotFoundException.php @@ -0,0 +1,12 @@ +<?php +namespace PartKeepr\StorageLocation\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +class StorageLocationNotFoundException extends SerializableException { + public function __construct () { + parent::__construct(PartKeepr::i18n("Storage Location not found.")); + } +} +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/StorageLocation/StorageLocation.php b/src/backend/PartKeepr/StorageLocation/StorageLocation.php @@ -0,0 +1,105 @@ +<?php +namespace PartKeepr\StorageLocation; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity; + +/** @Entity **/ +class StorageLocation extends BaseEntity implements Serializable, Deserializable { + /** + * Holds the name for our storage location + * @Column(type="string",unique=true) + * @var string + */ + private $name; + + /** + * Holds the storage location image + * @OneToOne(targetEntity="PartKeepr\StorageLocation\StorageLocationImage",mappedBy="storageLocation",cascade={"persist", "remove"}) + * @var StorageLocationImage + */ + private $image; + + /** + * Sets the name for the storage location + * @param string $name the name to set + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name of the storage location + * @return string The name + */ + public function getName () { + return $this->name; + } + + /** + * Sets the storage location image + * @param StorageLocationImage $image The storage location image + */ + public function setImage (StorageLocationImage $image) { + $this->image = $image; + $image->setStorageLocation($this); + } + + /** + * Returns the storage location image + * @return StorageLocationImage The storage location image + */ + public function getImage () { + return $this->image; + } + + /** + * Returns this storage location in serialized form + * @return array The serialized storage location + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "image_id" => is_object($this->getImage()) ? $this->getImage()->getId() : null); + } + + /** + * Deserializes the storage location + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "image_id": + if ($value == "") { + echo "/** Breaking because of empty value */"; + break; + } + + try { + $image = StorageLocationImage::loadById($value); + $this->setImage($image); + } catch (\Exception $e) { + if ($this->getImage()) { + // Image was not found, maybe a temporary image? + $this->getImage()->replaceFromTemporaryFile($value); + } else { + $image = StorageLocationImage::createFromTemporaryFile($value); + $this->setImage($image); + echo "/**"; + echo $image->getId(); + echo "*/"; + echo "/** FOO */"; + } + } + + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/StorageLocation/StorageLocationImage.php b/src/backend/PartKeepr/StorageLocation/StorageLocationImage.php @@ -0,0 +1,50 @@ +<?php +namespace PartKeepr\StorageLocation; + +use PartKeepr\Util\Serializable, + PartKeepr\Image\Image; + +/** + * Holds a storage location image + * @Entity + **/ +class StorageLocationImage extends Image implements Serializable { + /** + * The storage location object + * @OneToOne(targetEntity="PartKeepr\StorageLocation\StorageLocation",inversedBy="image") + * @var StorageLocation + */ + private $storageLocation = null; + + /** + * Creates a new storage location image instance + */ + public function __construct () { + parent::__construct(Image::IMAGE_STORAGELOCATION); + } + + /** + * Sets the storage location + * @param StorageLocation $storageLocation The storage location to set + */ + public function setStorageLocation (StorageLocation $storageLocation) { + $this->storageLocation = $storageLocation; + } + + /** + * Returns the storage location + * @return StorageLocation the storage location + */ + public function getStorageLocation () { + return $this->storageLocation; + } + + /** + * + * Serializes this storage location image + * @return array The serialized storage location image + */ + public function serialize () { + return array("id" => $this->getId(), "storageLocation_id" => $this->getStorageLocation()->getId()); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/StorageLocation/StorageLocationManager.php b/src/backend/PartKeepr/StorageLocation/StorageLocationManager.php @@ -0,0 +1,94 @@ +<?php +namespace PartKeepr\StorageLocation; + +use PartKeepr\Util\Singleton, + PartKeepr\StorageLocation\StorageLocation, + PartKeepr\PartKeepr, + PartKeepr\Category\CategoryManager, + PartKeepr\StorageLocation\Exceptions\StorageLocationNotFoundException; + +class StorageLocationManager extends Singleton { + public function getStorageLocations ($start = 0, $limit = 10, $sort = "footprint", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st.id, st.name")->from("PartKeepr\StorageLocation\StorageLocation","st"); + + if ($filter != "") { + $qb = $qb->where("LOWER(st.name) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\StorageLocation\StorageLocation","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "start" => $start, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + public function getStorageLocation ($id) { + $storageLocation = PartKeepr::getEM()->find("PartKeepr\StorageLocation\StorageLocation", $id); + + if ($storageLocation) { + return $storageLocation; + } else { + throw new StorageLocationNotFoundException(); + } + } + + public function getStorageLocationByName ($name) { + $query = PartKeepr::getEM()->createQuery("SELECT s FROM PartKeepr\StorageLocation\StorageLocation s WHERE s.name = :name"); + $query->setParameter("name", $name); + + return $query->getSingleResult(); + } + + public function addStorageLocation ($name) { + $storageLocation = new StorageLocation(); + $storageLocation->setName($name); + + PartKeepr::getEM()->persist($storageLocation); + PartKeepr::getEM()->flush(); + + return $storageLocation; + } + public function deleteStorageLocation ($id) { + $storageLocation = $this->getStorageLocation($id); + + PartKeepr::getEM()->remove($storageLocation); + PartKeepr::getEM()->flush(); + } + + public function getOrCreateStorageLocation ($storageLocation) { + if (is_int($storageLocation)) { + try { + return $this->getStorageLocation($storageLocation); + } catch (StorageLocationNotFoundException $e) {} + } + + $sl = new StorageLocation(); + $sl->setName($storageLocation); + + PartKeepr::getEM()->persist($sl); + + return $sl; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/StorageLocation/StorageLocationService.php b/src/backend/PartKeepr/StorageLocation/StorageLocationService.php @@ -0,0 +1,108 @@ +<?php +namespace PartKeepr\StorageLocation; + +use PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\Part\PartManager, + PartKeepr\Util\SerializableException, + PartKeepr\Stock\StockEntry, + PartKeepr\PartKeepr, + PartKeepr\Session\SessionManager; + +class StorageLocationService extends Service implements RestfulService { + + public function get () { + if ($this->hasParameter("id")) { + return array("data" => StorageLocationManager::getInstance()->getStorageLocation($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "name", + "direction" => "ASC"); + } + return StorageLocationManager::getInstance()->getStorageLocations( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + public function create () { + $this->requireParameter("name"); + + $storageLocation = new StorageLocation(); + $storageLocation->deserialize($this->getParameters()); + + PartKeepr::getEM()->persist($storageLocation); + + try { + PartKeepr::getEM()->flush(); + } catch (\PDOException $e) { + if ($e->getCode() == "23505") { + $exception = new SerializableException(sprintf(PartKeepr::i18n("Storage Location %s already exists!"), $storageLocation->getName())); + $exception->setDetail(sprintf(PartKeepr::i18n("You tried to add the storage location %s, but a storage location with the same name already exists."), $storageLocation->getName())); + + throw $exception; + } else { + throw $e; + } + } + + + return array("data" => $storageLocation->serialize()); + } + + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + $storageLocation = StorageLocationManager::getInstance()->getStorageLocation($this->getParameter("id")); + $storageLocation->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $storageLocation->serialize()); + + } + + public function destroy () { + $this->requireParameter("id"); + + StorageLocationManager::getInstance()->deleteStorageLocation($this->getParameter("id")); + + return array("data" => null); + } + + /** + * Creates multiple storage locations at once. + * + * Requires that the parameter "storageLocations" is set to an array with the names of the storage locations. + * Returns all error messages as "data" index in the result array. + */ + public function massCreate () { + $this->requireParameter("storageLocations"); + + $aMessages = array(); + + foreach ($this->getParameter("storageLocations") as $storageLocation) { + try { + $obj = StorageLocationManager::getInstance()->getStorageLocationByName($storageLocation); + $aMessages[] = sprintf(PartKeepr::i18n("Storage Location %s already exists"), $storageLocation); + } catch (\Exception $e) { + $obj = new StorageLocation(); + $obj->setName($storageLocation); + PartKeepr::getEM()->persist($obj); + } + + } + + PartKeepr::getEM()->flush(); + + return array("data" => $aMessages); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/System/SystemInformationRecord.php b/src/backend/PartKeepr/System/SystemInformationRecord.php @@ -0,0 +1,55 @@ +<?php +namespace PartKeepr\System; + +/** + * This class represents a system information record. + * + * This is basically a category, a name and a value. No logic included within + * the class. + * + * For example, records could hold: + * + * Name Value Category + * ===================================================================================== + * Doctrine ORM 2.1.0 Libraries + * Doctrine DBAL 2.1.0 Libraries + * Doctrine Migrations git-f87afe9223dbfecaaddb Libraries + * + * PHP Version 5.3.2 Server Software + * Operating System Linux (Funtoo Linux - baselayout 2.1.8) Server Software + + * @author felicitus + * + */ +class SystemInformationRecord { + /** + * Holds the category name + * @var string + */ + public $category; + + /** + * Holds the name + * @var string + */ + public $name; + + /** + * Holds the value + * @var mixed + */ + public $value; + + /** + * Creates a new system information record. + * + * @param string $name + * @param mixed $value + * @param string $category + */ + public function __construct ($name, $value, $category) { + $this->name = $name; + $this->value = $value; + $this->category = $category; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/System/SystemService.php b/src/backend/PartKeepr/System/SystemService.php @@ -0,0 +1,99 @@ +<?php +namespace PartKeepr\System; + +use PartKeepr\Util\Configuration, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\CronLogger\CronLoggerManager, + PartKeepr\Util\OS\OperatingSystem; + +class SystemService extends Service { + /** + * Returns a list of system information records. + * + * Please note that it is not defined which information is returned; the result + * should be seen as "informational" to the system operator, not for automated purposes. + */ + public function getSystemInformation () { + $aData = array(); + + $aData[] = new SystemInformationRecord("Doctrine ORM", \Doctrine\ORM\Version::VERSION, "Libraries"); + $aData[] = new SystemInformationRecord("Doctrine DBAL", \Doctrine\DBAL\Version::VERSION, "Libraries"); + + $aData[] = new SystemInformationRecord("PHP Version", phpversion(), "System"); + + $os = new OperatingSystem(); + + $aData[] = new SystemInformationRecord("Operating System Type", $os->getPlatform(), "System"); + $aData[] = new SystemInformationRecord("Operating System Release", $os->getRelease(), "System"); + + $aData[] = new SystemInformationRecord("memory_limit", ini_get("memory_limit"), "PHP"); + $aData[] = new SystemInformationRecord("post_max_size", ini_get("post_max_size"), "PHP"); + $aData[] = new SystemInformationRecord("upload_max_filesize", ini_get("upload_max_filesize"), "PHP"); + $aData[] = new SystemInformationRecord("post_max_size", ini_get("post_max_size"), "PHP"); + $aData[] = new SystemInformationRecord("allow_url_fopen", ini_get("allow_url_fopen"), "PHP"); + $aData[] = new SystemInformationRecord("max_execution_time", ini_get("max_execution_time"), "PHP"); + $aData[] = new SystemInformationRecord("APC enabled", (extension_loaded("apc") ? PartKeepr::i18n("Yes") : PartKeepr::i18n("No")), "PHP"); + + $aData[] = new SystemInformationRecord("PartKeepr Version", PartKeepr::getVersion(), "PartKeepr"); + + + foreach (Configuration::getOptions() as $key => $value) { + + // Hide passwords + if ($key == "partkeepr.database.password" || $key == "partkeepr.migration.partdb.password") { + $value = "<hidden>"; + } + + $aData[] = new SystemInformationRecord($key, $value, "PartKeepr Configuration Information"); + } + + return array("data" => $aData); + } + + /** + * Returns the database schema status. + * + * This method is usuall called once the user logs in, and alerts him if the schema is not up-to-date. + * + * Returns either status incomplete if the schema is not up-to-date, or complete if everything is OK. + */ + public function getSystemStatus () { + + if (Configuration::getOption("partkeepr.cronjobs.disablecheck", false) === true) { + // Skip cronjob tests + $inactiveCronjobs = array(); + } else { + $inactiveCronjobs = CronLoggerManager::getInstance()->getInactiveCronjobs(); + } + + + return array("data" => + array( + "inactiveCronjobCount" => count($inactiveCronjobs), + "inactiveCronjobs" => $inactiveCronjobs, + "schemaStatus" => $this->getSchemaStatus())); + } + + /** + * Checks if the schema is up-to-date. If yes, it returns "complete", if not, it returns "incomplete". + * + * @param none + * @return string Either "complete" or "incomplete" + */ + protected function getSchemaStatus () { + $metadatas = PartKeepr::getEM()->getMetadataFactory()->getAllMetadata(); + + $schemaTool = new \Doctrine\ORM\Tools\SchemaTool(PartKeepr::getEM()); + + $queries = $schemaTool->getUpdateSchemaSql($metadatas, true); + + if (count($queries) > 0) { + return "incomplete"; + } else { + return "complete"; + } + } + + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/SystemNotice/SystemNotice.php b/src/backend/PartKeepr/SystemNotice/SystemNotice.php @@ -0,0 +1,141 @@ +<?php +namespace PartKeepr\SystemNotice; + +use PartKeepr\UploadedFile\UploadedFile, + PartKeepr\Util\BaseEntity, + PartKeepr\Util\Serializable, + PartKeepr\Util\Deserializable; + +/** + * Holds a system notice + * @Entity + **/ +class SystemNotice extends BaseEntity implements Serializable { + /** + * @Column(type="datetime") + * @var \DateTime + */ + private $date; + + /** + * @Column(type="string") + * @var string + */ + private $title; + + /** + * The description of this attachment + * @Column(type="text") + * @var string + */ + private $description; + + /** + * Defines if the system notice has been acknowledged + * @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. + * @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 @@ -0,0 +1,55 @@ +<?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 @@ -0,0 +1,83 @@ +<?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 diff --git a/src/backend/PartKeepr/TempFile/TempFileService.php b/src/backend/PartKeepr/TempFile/TempFileService.php @@ -0,0 +1,72 @@ +<?php +namespace PartKeepr\TempFile; + +use PartKeepr\Service\Service; +use PartKeepr\UploadedFile\TempUploadedFile; +use PartKeepr\PartKeepr; + +class TempFileService extends Service { + + public function upload () { + $tmpFile = new TempUploadedFile(); + + if (array_key_exists("userfile", $_FILES) && file_exists($_FILES["userfile"]["tmp_name"])) { + $file = $_FILES['userfile']['tmp_name']; + $filename = $_FILES['userfile']['name']; + + $tmpFile->replace($file); + $tmpFile->setOriginalFilename(basename($filename)); + } elseif (array_key_exists("url", $_REQUEST)) { + $tmpFile->replaceFromURL($_REQUEST["url"]); + } else { + throw new \Exception("Error: No valid file given"); + } + + PartKeepr::getEM()->persist($tmpFile); + PartKeepr::getEM()->flush(); + + return array("id" => $tmpFile->getId(), "extension" => $tmpFile->getExtension(), "size" => $tmpFile->getSize(), "originalFilename" => $tmpFile->getOriginalFilename()); + } + + /** + * Receives a file via the service call. + * + * Parameters: + * - filedata: needs to be base64-encoded. + * - filename: The filename + */ + public function jsonUpload () { + $data = base64_decode($this->getParameter("filedata")); + $filename = $this->getParameter("filename"); + + $tempFile = tempnam("/tmp", "PWC"); + file_put_contents($tempFile, $data); + + $tmpFile = new TempUploadedFile(); + $tmpFile->replace($tempFile); + $tmpFile->setOriginalFilename($filename); + + PartKeepr::getEM()->persist($tmpFile); + PartKeepr::getEM()->flush(); + + return $tmpFile->serialize(); + } + + /** + * Processes data via HTTP POST. Reads php://input and creates a temporary image out of it. + */ + public function uploadCam () { + $tempFile = tempnam("/tmp", "PWC") . ".jpg"; + $result = file_put_contents( $tempFile, file_get_contents('php://input') ); + + $image = new TempUploadedFile(); + $image->replace($tempFile); + $image->setOriginalFilename(sprintf(PartKeepr::i18n("Cam photo of %s"), date("Y-m-d H:i:s")).".jpg"); + + PartKeepr::getEM()->persist($image); + PartKeepr::getEM()->flush(); + + return array("id" => $image->getId(), "extension" => $image->getExtension(), "size" => $image->getSize(), "originalFilename" => $image->getOriginalFilename()); + } +} + + \ No newline at end of file diff --git a/src/backend/PartKeepr/TempImage/TempImage.php b/src/backend/PartKeepr/TempImage/TempImage.php @@ -0,0 +1,19 @@ +<?php +namespace PartKeepr\TempImage; + +use PartKeepr\Image\Exceptions\InvalidImageTypeException, + PartKeepr\Util\Configuration, + PartKeepr\Image\Image, + PartKeepr\PartKeepr; + +/** + * Represents a temporary image. Temporary images are used when + * a user uploaded an image, but not attached it to an entity. + * + * @Entity + */ +class TempImage extends Image { + public function __construct () { + parent::__construct(Image::IMAGE_TEMP); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/TempImage/TempImageService.php b/src/backend/PartKeepr/TempImage/TempImageService.php @@ -0,0 +1,30 @@ +<?php +namespace PartKeepr\TempImage; + +use PartKeepr\Service\Service; +use PartKeepr\TempImage\TempImage; +use PartKeepr\PartKeepr; + +class TempImageService extends Service { + public function upload () { + $image = new TempImage(); + + if (array_key_exists("userfile", $_FILES) && file_exists($_FILES["userfile"]["tmp_name"])) { + $file = $_FILES['userfile']['tmp_name']; + $filename = $_FILES['userfile']['name']; + + $image->replace($file); + $image->setOriginalFilename(basename($filename)); + } elseif (array_key_exists("url", $_REQUEST)) { + $image->replaceFromURL($_REQUEST["url"]); + } else { + throw new \Exception("Error: No valid file given"); + } + + PartKeepr::getEM()->persist($image); + PartKeepr::getEM()->flush(); + + return array("id" => $image->getId(), "extension" => $image->getExtension(), "size" => $image->getSize(), "originalFilename" => $image->getOriginalFilename()); + } +} + + \ No newline at end of file diff --git a/src/backend/PartKeepr/TipOfTheDay/TipOfTheDay.php b/src/backend/PartKeepr/TipOfTheDay/TipOfTheDay.php @@ -0,0 +1,114 @@ +<?php +namespace PartKeepr\TipOfTheDay; + +use PartKeepr\Util\Serializable; + +use PartKeepr\PartKeepr; + +use PartKeepr\Util\Configuration; + +use PartKeepr\Util\BaseEntity; + +/** + * Represents a tip of the day. + * + * Tips are stored on the central PartKeepr server in a wiki. However, we need to know a list of all tip pages + * because the API has a limit per day. So basically, we sync the tip names from the wiki to the local system several + * times a day and not each time an user logs in. + * + * Note: If you wish to link against a tip of the day, do it by name and not by id! + * + * @Entity + **/ +class TipOfTheDay extends BaseEntity implements Serializable { + /** + * @Column(type="string") + * @var string + */ + private $name; + + /** + * Sets the name for this tip + * @param string $name The name + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name for this tip + * @return string The name + */ + public function getName () { + return $this->name; + } + + /** + * Syncronizes the tip database against the master wiki. + * @throws \Exception + */ + public static function syncTips () { + if (ini_get("allow_url_fopen") == 0) { + throw new \Exception("allow_url_fopen is disabled, but required to query the TipOfTheDay database."); + } + + $url = Configuration::getOption("partkeepr.tipoftheday.api", "http://partkeepr.org/wiki/api.php?action=query&list=categorymembers&cmtitle=Category:TipOfTheDay&format=json"); + + $tipsString = file_get_contents($url); + + + $aPageNames = self::extractPageNames($tipsString); + + self::updateTipDatabase($aPageNames); + } + + /** + * Updates the tip database. Expects an array of page names. + * + * This method clears all page names and re-creates them. This saves + * alot of engineering, because we don't need to match contents + * within the database against contents in an array. + * + * @param array $aPageNames The page names as array. Page names are stored as string. + */ + private static function updateTipDatabase (array $aPageNames) { + $dql = "DELETE FROM PartKeepr\TipOfTheDay\TipOfTheDay"; + $query = PartKeepr::getEM()->createQuery($dql); + + $query->execute(); + + foreach ($aPageNames as $pageName) { + $tip = new TipOfTheDay(); + $tip->setName($pageName); + PartKeepr::getEM()->persist($tip); + } + + PartKeepr::getEM()->flush(); + } + + /** + * Extracts the page names from the mediawiki JSON returned. + * @param string $response The encoded json string + * @return array An array with the titles of each page + */ + private static function extractPageNames ($response) { + $aTipsStructure = json_decode($response, true); + $aTips = $aTipsStructure["query"]["categorymembers"]; + + $aPageNames = array(); + + foreach ($aTips as $tip) { + $aPageNames[] = $tip["title"]; + } + + return $aPageNames; + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( "name" => $this->getName() ); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/TipOfTheDay/TipOfTheDayHistory.php b/src/backend/PartKeepr/TipOfTheDay/TipOfTheDayHistory.php @@ -0,0 +1,51 @@ +<?php +namespace PartKeepr\TipOfTheDay; + +use PartKeepr\User\User; + +use PartKeepr\Util\Serializable; + +use PartKeepr\PartKeepr; + +use PartKeepr\Util\Configuration; + +use PartKeepr\Util\BaseEntity; + +/** + * Represents a tip of the day history entry. + * + * This entity stores each tip of the day the user has already seen. + * + * @Entity + **/ +class TipOfTheDayHistory extends BaseEntity { + /** + * @Column(type="string") + * @var string + */ + private $name; + + /** + * Defines the user + * @ManyToOne(targetEntity="PartKeepr\User\User") + * @var StorageLocation + */ + private $user; + + /** + * Sets the user for this entry + * @param User $user + */ + public function setUser (User $user) { + $this->user = $user; + } + + /** + * Sets the tip of the day name the user already has seen + * @param string $name The tip name + */ + public function setName ($name) { + $this->name = $name; + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/TipOfTheDay/TipOfTheDayService.php b/src/backend/PartKeepr/TipOfTheDay/TipOfTheDayService.php @@ -0,0 +1,86 @@ +<?php +namespace PartKeepr\TipOfTheDay; + +use PartKeepr\Util\Configuration, + PartKeepr\User\User, + PartKeepr\Service\RestfulService, + PartKeepr\Session\SessionManager, + PartKeepr\Service\Service, + PartKeepr\PartKeepr; + +class TipOfTheDayService extends Service implements RestfulService { + /** + * Returns all tips along with the information wether they are read or not. + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + $aTips = array(); + $url = Configuration::getOption("partkeepr.tipoftheday.wiki", "http://partkeepr.org/wiki/index.php/"); + + /* Extract all tips which aren't read */ + $dql = "SELECT d FROM PartKeepr\TipOfTheDay\TipOfTheDay d WHERE d.name NOT IN "; + $dql .= "(SELECT dh.name FROM PartKeepr\TipOfTheDay\TipOfTheDayHistory dh WHERE dh.user = :user)"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", SessionManager::getCurrentSession()->getUser()); + + foreach ($query->getResult() as $result) { + $aTips[] = array ( + "name" => $result->getName(), + "read" => false, + "url" => $url.$result->getName() . "?useskin=monobookplain"); + } + + /* Extract all tips which are read */ + $dql = "SELECT d FROM PartKeepr\TipOfTheDay\TipOfTheDay d WHERE d.name IN "; + $dql .= "(SELECT dh.name FROM PartKeepr\TipOfTheDay\TipOfTheDayHistory dh WHERE dh.user = :user)"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", SessionManager::getCurrentSession()->getUser()); + + foreach ($query->getResult() as $result) { + $aTips[] = array ( + "name" => $result->getName(), + "read" => true, + "url" => $url.$result->getName() . "?useskin=monobookplain"); + } + + return array("data" => $aTips); + } + + public function create() {} + public function update () {} + public function destroy () {} + + /** + * Marks a specific tip as read. + * + * Uses the parameter "name" to identify the tip. + */ + public function markTipAsRead () { + $this->requireParameter("name"); + + try { + $th = new TipOfTheDayHistory; + $th->setUser($this->getUser()); + $th->setName($this->getParameter("name")); + + PartKeepr::getEM()->persist($th); + PartKeepr::getEM()->flush(); + } catch (\Exception $e) { + /* Do nothing */ + } + + } + + /** + * Marks all tips as unread for the current user + */ + public function markAllTipsAsUnread () { + $dql = "DELETE FROM PartKeepr\TipOfTheDay\TipOfTheDayHistory th WHERE th.user = :user"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", $this->getUser()); + $query->execute(); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Unit/Unit.php b/src/backend/PartKeepr/Unit/Unit.php @@ -0,0 +1,130 @@ +<?php +namespace PartKeepr\Unit; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr, + PartKeepr\Util\Exceptions\OutOfRangeException, + PartKeepr\SiPrefix\SiPrefix; + + +/** + * This object represents an unit. Units can be: Volt, Hertz etc. + * + * @Entity + **/ +class Unit extends BaseEntity implements Serializable, Deserializable { + /** + * The name of the unit (e.g. Volts, Ampere, Farad, Metres) + * @Column(type="string") + * @var string + */ + private $name; + + /** + * The symbol of the unit (e.g. V, A, F, m) + * @Column(type="string") + * @var string + */ + private $symbol; + + /** + * Defines the allowed SiPrefixes for this parameter unit + * @ManyToMany(targetEntity="PartKeepr\SiPrefix\SiPrefix") + * @JoinTable(name="UnitSiPrefixes", + * joinColumns={@JoinColumn(name="unit_id", referencedColumnName="id")}, + * inverseJoinColumns={@JoinColumn(name="siprefix_id", referencedColumnName="id")} + * ) + * @var ArrayCollection + */ + private $prefixes; + + /** + * Creates a new Unit. + */ + public function __construct () { + $this->prefixes = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Sets the name for this unit + * @param string $name the name for this unit + */ + public function setName ($name) { + $this->name = $name; + } + + /** + * Returns the name for this unit + * @return string The unit name + */ + public function getName () { + return $this->name; + } + + /** + * Sets the symbol for this unit + * @param string $symbol The symbol + */ + public function setSymbol ($symbol) { + $this->symbol = $symbol; + } + + /** + * Returns the symbol for this unit + * @return string The symbol + */ + public function getSymbol () { + return $this->symbol; + } + + /** + * Returns the si-prefix list for this unit + * @return array An array of SiPrefix objects + */ + public function getPrefixes () { + return $this->prefixes; + } + + /** + * Serializes the user object and returns it as array, suitable + * to process via json_encode. + * @param none + * @return array An array containing the object information + */ + public function serialize () { + return array( + "id" => $this->getId(), + "name" => $this->getName(), + "symbol" => $this->getSymbol(), + "prefixes" => $this->serializeChildren($this->getPrefixes()) + ); + } + + /** + * Deserializes the unit + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "name": + $this->setName($value); + break; + case "symbol": + $this->setSymbol($value); + break; + case "prefixes": + $prefixes = $this->getPrefixes(); + $prefixes->clear(); + + foreach ($value as $prefix) { + $prefix = SiPrefix::loadById($prefix["id"]); + $prefixes->add($prefix); + } + break; + } + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Unit/UnitManager.php b/src/backend/PartKeepr/Unit/UnitManager.php @@ -0,0 +1,99 @@ +<?php +namespace PartKeepr\Unit; + +use PartKeepr\Util\Singleton, + PartKeepr\PartKeepr, + PartKeepr\Unit\Exceptions\UnitNotFoundException; + +class UnitManager extends Singleton { + public function getUnits ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("u.id, u.name, u.symbol")->from("PartKeepr\Unit\Unit","u"); + + if ($filter != "") { + $qb = $qb->where("LOWER(u.name) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("u.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(u.id)")->from("PartKeepr\Unit\Unit","u"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(u.name) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + foreach ($result as $key => $value) { + $result[$key]["prefixes"] = $this->getSiPrefixes($value["id"]); + } + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + public function getSiPrefixes ($id) { + $unit = UnitManager::getInstance()->getUnit($id); + + $aData = array(); + + foreach ($unit->getPrefixes() as $prefix) { + $aData[] = $prefix->serialize(); + } + + return array("response" => array("totalCount" => count($aData), "data" => $aData)); + } + + public function getUnitByName ($name) { + $dql = "SELECT u FROM PartKeepr\Unit\Unit u WHERE u.name = :name"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $name); + + return $query->getSingleResult(); + } + + public function unitExists ($name) { + $dql = "SELECT COUNT(u) FROM PartKeepr\Unit\Unit u WHERE u.name = :name"; + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $name); + + if ($query->getSingleScalarResult() == 0) { + return false; + } else { + return true; + } + } + + public function getUnit ($id) { + $unit = PartKeepr::getEM()->find("PartKeepr\Unit\Unit", $id); + + if ($unit) { + return $unit; + } else { + throw new UnitNotFoundException(); + } + } + + public function deleteUnit ($id) { + $unit = $this->getUnit($id); + + PartKeepr::getEM()->remove($unit); + PartKeepr::getEM()->flush(); + } + + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Unit/UnitService.php b/src/backend/PartKeepr/Unit/UnitService.php @@ -0,0 +1,67 @@ +<?php +namespace PartKeepr\Unit; + +use PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Part\PartUnit, + PartKeepr\SiPrefix\SiPrefix, + PartKeepr\Session\SessionManager; + +class UnitService extends Service implements RestfulService { + public function get () { + if ($this->hasParameter("id")) { + return array("data" => UnitManager::getInstance()->getUnit($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "name", + "direction" => "ASC"); + } + return UnitManager::getInstance()->getUnits( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + public function create () { + $this->requireParameter("name"); + + $unit = new Unit; + $unit->deserialize($this->getParameters()); + + PartKeepr::getEM()->persist($unit); + PartKeepr::getEM()->flush(); + + return array("data" => $unit->serialize()); + } + + public function update () { + $this->requireParameter("id"); + $this->requireParameter("name"); + + $unit = UnitManager::getInstance()->getUnit($this->getParameter("id")); + $unit->deserialize($this->getParameters()); + + PartKeepr::getEM()->flush(); + + return array("data" => $unit->serialize()); + + } + + public function destroy () { + $this->requireParameter("id"); + + UnitManager::getInstance()->deleteUnit($this->getParameter("id")); + + return array("data" => null); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/UploadedFile/TempUploadedFile.php b/src/backend/PartKeepr/UploadedFile/TempUploadedFile.php @@ -0,0 +1,15 @@ +<?php +namespace PartKeepr\UploadedFile; + +/** + * Represents a temporary file. Temporary files are used when + * a user uploaded a file, but not attached it to an entity. + * + * @Entity + */ +class TempUploadedFile extends UploadedFile { + public function __construct () { + parent::__construct(); + $this->setType("Temporary"); + } +} diff --git a/src/backend/PartKeepr/UploadedFile/UploadedFile.php b/src/backend/PartKeepr/UploadedFile/UploadedFile.php @@ -0,0 +1,301 @@ +<?php +namespace PartKeepr\UploadedFile; + +use PartKeepr\Util\SerializableException, + PartKeepr\Util\BaseEntity, + PartKeepr\Util\Serializable, + PartKeepr\PartKeepr, + PartKeepr\UploadedFile\TempUploadedFile, + PartKeepr\Util\Configuration; + +/** + * @MappedSuperclass + */ +abstract class UploadedFile extends BaseEntity implements Serializable { + /** + * Specifies the type of the file. + * + * @var string + * @Column(type="string") + **/ + private $type; + + /** + * The unique filename of the file + * + * @var string + * @Column(type="string") + */ + private $filename; + + /** + * The original name of the file + * @Column(type="string",nullable=true) + * @var string + */ + private $originalname; + + /** + * The mimetype for the file + * @var string + * @Column(type="string") + */ + private $mimetype; + + /** + * The size of the uploaded file + * @Column(type="integer") + * @var integer + */ + private $size; + + /** + * Constructs a new file object. + * + */ + public function __construct () { + $this->filename = PartKeepr::createGUIDv4(); + } + + /** + * Sets the type of the file. Once the type is set, + * it may not be changed later. + */ + protected function setType ($type) { + $this->type = $type; + } + + /** + * Returns the original filename + * @return string The original filename + */ + public function getOriginalFilename () { + return $this->originalname; + } + + /** + * Sets the original filename + * @param string $filename The original filename + */ + public function setOriginalFilename ($filename) { + $this->originalname = $filename; + } + + /** + * Replaces the current file with a new file. + * + * @param string $path The path to the original file + */ + public function replace ($path) { + // Parse the file's mimetype + $finfo = new \finfo(FILEINFO_MIME); + $this->mimetype = $finfo->file($path, FILEINFO_MIME_TYPE); + + // Get the file size + $this->size = filesize($path); + + $this->ensureFilePathExists(); + $this->checkPermissions(); + + copy($path, $this->getFilename()); + + $this->setOriginalFilename(basename($path)); + } + + /** + * Replaces the file from an URL. Does some tricks to avoid 403 forbidden on some sites. + * @param string $url + */ + public function replaceFromURL ($url) { + + /* Some sites don't like automated requests. But the internet is meant to be open for anybody, + * even for scripts. So we are evil and fake the headers. + * + * Credit goes to Ryan Rampersad from whom I copied most code. + * http://blog.ryanrampersad.com/2008/11/07/get-remote-html-with-curl-and-php/ + */ + $curl = curl_init(); + + $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,"; + $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; + $header[] = "Cache-Control: max-age=0"; + $header[] = "Connection: keep-alive"; + $header[] = "Keep-Alive: 300"; + $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"; + $header[] = "Accept-Language: en-us,en;q=0.5"; + $header[] = "Pragma: "; + + $browser = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3"; + + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_USERAGENT, $browser); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_TIMEOUT, 30); + curl_setopt($curl, CURLOPT_MAXREDIRS, 7); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + + $data = curl_exec($curl); + + if ($data === false) { + throw new \Exception("replaceFromURL error: ".curl_error($curl)); + } + + curl_close($curl); + + $tempName = tempnam("/tmp", "PARTKEEPR"); + + file_put_contents($tempName, $data); + + $this->replace($tempName); + + $this->setOriginalFilename(basename($url)); + } + + /** + * Returns the size of this file + * @return integer The size in bytes + */ + public function getSize () { + return $this->size; + } + + /** + * Returns the type of the file + * @param none + * @return string The type of the file + */ + public function getType () { + return $this->type; + } + + /** + * Returns the full filename including path and suffix. + * @return string The full filename + */ + public function getFilename () { + return $this->getFilePath().$this->filename.".".$this->getExtension(); + } + + /** + * Returns the plain filename without path and suffix. + * @return string the plain filename + */ + public function getPlainFilename () { + return $this->filename; + } + + /** + * Returns the mime type for this file + * @return string The mimetype for this file, e.g. text/plain + */ + public function getMimeType () { + return $this->mimetype; + } + + /** + * Returns the extension for the given mime type. + * + * This function simply extracts that information from the mime type; + * special cases are not handled. e.g. if you have image/foobar, it would + * return "foobar" as extension. + * + * @return string The extension + */ + public function getExtension () { + list($category, $type) = explode("/", $this->getMimeType()); + return $type; + } + + /** + * Returns the path to the file. May be overridden by + * subclasses. + * + * @param none + * @return string The path to the file + */ + public function getFilePath () { + return Configuration::getOption( + "partkeepr.files.path", + PartKeepr::getRootDirectory() . "/data/") . $this->getType() . "/"; + } + + /** + * Ensures that the file path exists. This function + * is called every time a file is processed. + * It is maybe a bit overhead, but saves headaches later when + * introducing new types. + * + * @param none + * @return nothing + */ + public function ensureFilePathExists () { + if (!is_dir($this->getFilePath())) { + try { + mkdir($this->getFilePath(), 0777, true); + } catch (\Exception $e) { + throw new \Exception("Unable to create directory ".$this->getFilePath()); + } + } + } + + /** + * Creates a new entity from the given temporary id. + * + * @param string $id The temporary id (prefixed with TMP:) + * @return object a new instance of the file. + * @throws \Exception If the ID does not begin with TMP: + */ + public static function createFromTemporaryFile ($id) { + if (substr($id, 0, 4) === "TMP:") { + // It's a temporary file + $className = get_called_class(); + + $file = new $className(); + $file->replaceFromTemporaryFile($id); + return $file; + } else { + throw new \Exception("Given id $id is not a temporary file"); + } + } + + /** + * Replaces the file with a given temporary file. + * @param string $id The temporary id (prefixed with TMP:) + */ + public function replaceFromTemporaryFile ($id) { + if (substr($id, 0, 4) === "TMP:") { + $tmpFileId = str_replace("TMP:", "", $id); + $tmpFile = TempUploadedFile::loadById($tmpFileId); + + $this->replace($tmpFile->getFilename()); + $this->setOriginalFilename($tmpFile->getOriginalFilename()); + } + } + + /** + * Checks if the path where the file should be stored has sufficient permissions to do so. + * + * @throws SerializableException + */ + public function checkPermissions () { + if (!is_writable($this->getFilePath())) { + throw new SerializableException( + sprintf(PartKeepr::i18n("Unable to write to directory %s"), $this->getFilePath())); + } + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "id" => $this->getId(), + "extension" => $this->getExtension(), + "size" => $this->getSize(), + "originalFilename" => $this->getOriginalFilename() + ); + } +} diff --git a/src/backend/PartKeepr/User/Exceptions/InvalidLoginDataException.php b/src/backend/PartKeepr/User/Exceptions/InvalidLoginDataException.php @@ -0,0 +1,14 @@ +<?php +namespace PartKeepr\User\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** + * Is thrown when the user has given wrong credentials. + */ +class InvalidLoginDataException extends SerializableException { + public function __construct () { + parent::__construct(PartKeepr::i18n("Username or Password wrong.")); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/User/Exceptions/UserAlreadyExistsException.php b/src/backend/PartKeepr/User/Exceptions/UserAlreadyExistsException.php @@ -0,0 +1,19 @@ +<?php +namespace PartKeepr\User\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** +* Is thrown when the user already exists. This usually happens +* if someone tries to create a user with the same name of an existing +* user. +*/ +class UserAlreadyExistsException extends SerializableException { + public function __construct ($username) { + parent::__construct( + sprintf( + PartKeepr::i18n("User %s already exists."), + $username)); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/User/Exceptions/UserDoesNotExistException.php b/src/backend/PartKeepr/User/Exceptions/UserDoesNotExistException.php @@ -0,0 +1,17 @@ +<?php +namespace PartKeepr\User\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** +* Is thrown when the user doesn't exist. +*/ +class UserDoesNotExistException extends SerializableException { + public function __construct ($username) { + parent::__construct( + sprintf( + PartKeepr::i18n("The user %s doesn't exist. Maybe the user was already deleted."), + $username)); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/User/User.php b/src/backend/PartKeepr/User/User.php @@ -0,0 +1,259 @@ +<?php +namespace PartKeepr\User; + +use PartKeepr\UserPreference\UserPreference; + +use PartKeepr\Util\Deserializable, + PartKeepr\Util\Serializable, + PartKeepr\Util\BaseEntity, + PartKeepr\PartKeepr; + +/** @Entity @Table(name="PartKeeprUser") */ +class User extends BaseEntity implements Serializable, Deserializable { + /** @Column(length=50,unique=true) */ + private $username; + + /** @Column(length=32) */ + private $password; + + /** @Column(type="boolean") */ + private $admin; + + /** + * Creates a new user object. + * + * @param string $username The username to set (optional) + * @param string $password The password to set (optional) + */ + public function __construct ($username = null, $password = null) { + if ($username !== null) { + $this->setUsername($username); + } + + if ($password !== null) { + $this->setPassword($password); + } + + $this->setAdmin(false); + } + + /** + * Sets the username. + * + * Forces the username to have + * lowercase a-z characters. + * + * Replaces space with an underscore. + * Replaces dot with nothing. + * + * @param string $username The username to set. Applies automatic username modification. + * @return nothing + */ + public function setUsername ($username) { + $username = strtolower($username); + $username = str_replace(" ", "_", $username); + $username = str_replace(".", "", $username); + + $this->username = $username; + + } + + /** + * Sets the raw username, without replacing any special chars. + * + * This method should only be used for building a temporary user + * for login checks. + * + * @param string $username The raw username + * @return nothing + */ + public function setRawUsername ($username) { + $this->username = $username; + } + + /** + * Returns the username. + * @param none + * @return string The username + */ + public function getUsername () { + return $this->username; + } + + /** + * Sets the admin flag + * @param boolean $bAdmin True if the user is an admin, false otherwise + */ + public function setAdmin ($bAdmin) { + $this->admin = (boolean)$bAdmin; + } + + /** + * Returns the admin flag + * @return boolean True if the user is an admin + */ + public function isAdmin () { + return $this->admin; + } + + /** + * Sets the user's password. Automatically + * applies md5 hashing. + * + * @param string $password + */ + public function setPassword ($password) { + $this->setHashedPassword(md5($password)); + } + + /** + * Returns the user's md5-hashed password. + * @param none + * @return string The md5-hashed password + */ + public function getHashedPassword () { + return $this->password; + } + + /** + * Sets the user's password. Expects a hash + * and does not apply md5 hasing. + * + * @param string $hashedPassword + */ + public function setHashedPassword ($hashedPassword) { + $this->password = $hashedPassword; + } + + /** + * Compares the given un-hashed password with the + * object's hashed password. + * + * + * @param string $password The unhashed password + * @return boolean true if the passwords match, false otherwise + */ + public function comparePassword ($password) { + return $this->compareHashedPassword(md5($password)); + } + + /** + * Compares the given hashed password with the object's + * hashed password. + * + * @param string $hashedPassword The md5-hashed password + * @return boolean true if the passwords match, false otherwise + */ + public function compareHashedPassword ($hashedPassword) { + if ($hashedPassword == $this->password) { + return true; + } else { + return false; + } + } + + /** + * Serializes the user object and returns it as array, suitable + * to process via json_encode. + * @param none + * @return array An array containing the object information + */ + public function serialize () { + return array( + "id" => $this->getId(), + "username" => $this->getUsername() + ); + } + + /** + * Deserializes the user + * @param array $parameters The array with the parameters to set + */ + public function deserialize (array $parameters) { + foreach ($parameters as $key => $value) { + switch ($key) { + case "username": + $this->setUsername($value); + break; + case "password": + if ($value !== "") { + $this->setPassword($value); + } + break; + } + } + } + + /** + * Sets a user preference + * + * @param string $preferenceKey The preference key + * @param string $preferenceValue The preference value + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public function setPreference ($preferenceKey, $preferenceValue) { + return UserPreference::setPreference($this, $preferenceKey, $preferenceValue); + } + + /** + * Returns a given preference object + * + * @param string $preferenceKey The preference key + * @return UserPreference The user preference object + * @throws UserPreferenceNotFoundException If the preference key was not found + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public function getPreference ($preferenceKey) { + return UserPreference::getPreference($this, $preferenceKey); + } + + /** + * Returns a given preference value + * + * @param string $preferenceKey The preference key + * @return UserPreference The user preference object + * @throws UserPreferenceNotFoundException If the preference key was not found + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public function getPreferenceValue ($preferenceKey) { + return UserPreference::getPreferenceValue($this, $preferenceKey); + } + + /** + * Deletes the given preference + * + * @param string $preferenceKey The preference key + * @return UserPreference The user preference object + * @throws UserPreferenceNotFoundException If the preference key was not found + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public function deletePreference ($preferenceKey) { + UserPreference::deletePreference($this, $preferenceKey); + } + + /** + * Returns all user preferences for this user + * + * @param none + * @return Array An array of UserPreference objects + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public function getPreferences () { + return UserPreference::getPreferences($this); + } + /** + * Loads a user by name. + * + * @param $username string The username to query + * @return User A user object + * @throws Doctrine\ORM\NoResultException If no user was found + */ + public static function loadByName ($username) { + $dql = "SELECT u FROM PartKeepr\User\User u WHERE u.username = :username"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("username", $username); + + return $query->getSingleResult(); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/User/UserManager.php b/src/backend/PartKeepr/User/UserManager.php @@ -0,0 +1,135 @@ +<?php +namespace PartKeepr\User; + +use PartKeepr\Util\Singleton, + PartKeepr\User\User, + PartKeepr\PartKeepr, + PartKeepr\User\Exceptions\InvalidLoginDataException, + PartKeepr\Category\CategoryManager, + PartKeepr\User\Exceptions\UserAlreadyExistsException, + PartKeepr\User\Exceptions\UserNotFoundException; + +class UserManager extends Singleton { + /** + * Returns a list of users. + * + * @param int $start Start of the list, default 0 + * @param int $limit Number of users to list, default 10 + * @param string $sort The field to sort by, default "name" + * @param string $dir The direction to sort (ASC or DESC), default ASC + * @param string $filter A string to filter the user's name by, default empty + */ + public function getUsers ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { + + $qb = PartKeepr::getEM()->createQueryBuilder(); + $qb->select("st.id, st.username")->from("PartKeepr\User\User","st"); + + if ($filter != "") { + $qb = $qb->where("LOWER(st.username) LIKE :filter"); + $qb->setParameter("filter", "%".strtolower($filter)."%"); + } + + if ($limit > -1) { + $qb->setMaxResults($limit); + $qb->setFirstResult($start); + } + + $qb->orderBy("st.".$sort, $dir); + + $query = $qb->getQuery(); + + $result = $query->getResult(); + + $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); + $totalQueryBuilder->select("COUNT(st.id)")->from("PartKeepr\User\User","st"); + + + + if ($filter != "") { + $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.username) LIKE :filter"); + $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); + } + + $totalQuery = $totalQueryBuilder->getQuery(); + + return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); + } + + /** + * Checks if the passed user already exists. + * + * @param $username string The username to check + */ + public function userExists ($username) { + $dql = "SELECT COUNT(u) FROM PartKeepr\User\User u WHERE u.username = :name"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("name", $username); + + $count = $query->getSingleScalarResult(); + + if ($count == 0) { + return false; + } else { + return true; + } + } + + /** + * Creates the given user. Checks if the user already exists + * + * @param User $user The user to create + * @throws UserAlreadyExistsException + */ + public function createUser (User $user) { + if ($this->userExists($user->getUsername())) { + throw new UserAlreadyExistsException($user->getUsername()); + } + + PartKeepr::getEM()->persist($user); + PartKeepr::getEM()->flush(); + } + + /** + * Returns the user for a given user id + * @param integer $id The user id + */ + public function getUser ($id) { + return User::loadById($id); + } + + /** + * Deletes an user by id + * @param int $id The user's id + */ + public function deleteUser ($id) { + $user = User::loadById($id); + + PartKeepr::getEM()->remove($user); + PartKeepr::getEM()->flush(); + } + + /** + * Authenticates the given user. If successful, an instance + * of the user is returned. + * + * @param User $user The user to authenticate + * @throws InvalidLoginDataException Thrown if the user's credentials are not valid + */ + public function authenticate (User $user) { + $result = PartKeepr::getEM() + ->getRepository("PartKeepr\User\User") + ->findOneBy( + array( + "username" => $user->getUsername(), + "password" => $user->getHashedPassword() + ) + ); + + if ($result == null) { + throw new InvalidLoginDataException(); + } else { + return $result; + } + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/User/UserService.php b/src/backend/PartKeepr/User/UserService.php @@ -0,0 +1,101 @@ +<?php +namespace PartKeepr\User; + +use PartKeepr\Service\RestfulService, + PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\User\User, + PartKeepr\Session\SessionManager; + +class UserService extends Service implements RestfulService { + + /** + * Implements the get() call for the RestfulService. + * + * If the "id" parameter is passed, try to return the user by id. If not, + * return a list. + * + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + if ($this->hasParameter("id")) { + if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { + throw new \Exception("Permission denied"); + } + + return array("data" => UserManager::getInstance()->getUser($this->getParameter("id"))->serialize()); + } else { + if ($this->hasParameter("sort")) { + $tmp = json_decode($this->getParameter("sort"), true); + + $aSortParams = $tmp[0]; + } else { + $aSortParams = array( + "property" => "username", + "direction" => "ASC"); + } + return UserManager::getInstance()->getUsers( + $this->getParameter("start", $this->getParameter("start", 0)), + $this->getParameter("limit", $this->getParameter("limit", 25)), + $this->getParameter("sortby", $aSortParams["property"]), + $this->getParameter("dir", $aSortParams["direction"]), + $this->getParameter("query", "")); + } + } + + /** + * Creates a new user. + * + * @see PartKeepr\Service.RestfulService::create() + */ + public function create () { + if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { + throw new \Exception("Permission denied"); + } + + $this->requireParameter("username"); + + $user = new User; + $user->deserialize($this->getParameters()); + + UserManager::getInstance()->createUser($user); + + return array("data" => $user->serialize()); + } + + /** + * Updates the user informations. + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { + throw new \Exception("Permission denied"); + } + + $this->requireParameter("id"); + $this->requireParameter("username"); + $user = UserManager::getInstance()->getUser($this->getParameter("id")); + + $user->deserialize($this->getParameters()); + PartKeepr::getEM()->flush(); + + return array("data" => $user->serialize()); + + } + + /** + * Deletes the user from the database. + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { + throw new \Exception("Permission denied"); + } + + $this->requireParameter("id"); + + UserManager::getInstance()->deleteUser($this->getParameter("id")); + + return array("data" => null); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/UserPreference/Exceptions/UserPreferenceNotFoundException.php b/src/backend/PartKeepr/UserPreference/Exceptions/UserPreferenceNotFoundException.php @@ -0,0 +1,20 @@ +<?php +namespace PartKeepr\UserPreference\Exceptions; + +use PartKeepr\User\User, + PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** + * Is thrown when the user has given wrong credentials. + */ +class UserPreferenceNotFoundException extends SerializableException { + public function __construct (User $user, $preferenceKey) { + $message = sprintf( PartKeepr::i18n("User preference %s not found for user %s (%s)"), + $preferenceKey, + $user->getUsername(), + $user->getId()); + + parent::__construct($message); + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/UserPreference/UserPreference.php b/src/backend/PartKeepr/UserPreference/UserPreference.php @@ -0,0 +1,229 @@ +<?php +namespace PartKeepr\UserPreference; + +use PartKeepr\Util\Serializable, + PartKeepr\PartKeepr, + PartKeepr\User\User, + PartKeepr\Util\Configuration, + PartKeepr\Util\BaseEntity, + PartKeepr\UserPreference\Exceptions\UserPreferenceNotFoundException, + PartKeepr\Util\Exceptions\EntityNotPersistantException, + Doctrine\ORM\NoResultException; + +/** + * Represents a user preference entry. + * + * User preferences are a simple key => value mechanism, where the developer can + * specify the key and value himself. + * + * Note that values are stored internally as serialized PHP values to keep their type. + * + * @Entity + **/ +class UserPreference implements Serializable { + /** + * Defines the key of the user preference + * @Column(type="string",length=255) + * @Id + * @var string + */ + private $preferenceKey; + + /** + * Defines the value. Note that the value is internally stored as a serialized string. + * @Column(type="text") + * @var mixed + */ + private $preferenceValue; + + /** + * Defines the user + * @ManyToOne(targetEntity="PartKeepr\User\User") + * @Id + * @var User + */ + private $user; + + + /** + * Sets the user for this entry + * @param User $user + */ + public function setUser (User $user) { + $this->user = $user; + } + + /** + * Returns the user associated with this entry + * @return \PartKeepr\User\User + */ + public function getUser () { + return $this->user; + } + + /** + * Sets the key for this user preference + * @param string $key The key name + */ + public function setKey ($key) { + $this->preferenceKey = $key; + } + + /** + * Returns the key of this entry + * @return string + */ + public function getKey () { + return $this->preferenceKey; + } + + /** + * Sets the value for this entry + * @param mixed $value + */ + public function setValue ($value) { + $this->preferenceValue = serialize($value); + } + + /** + * Returns the value for this entry + * @return mixed The value + */ + public function getValue () { + return unserialize($this->preferenceValue); + } + + /** + * (non-PHPdoc) + * @see PartKeepr\Util.Serializable::serialize() + */ + public function serialize () { + return array( + "key" => $this->getKey(), + "value" => $this->getValue(), + "user_id" => $this->getUser()->getId() + ); + } + + /** + * Creates or updates a preference for a given user. + * + * @param User $user The user to set the preference for + * @param string $key The key to set + * @param string $value The value to set + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public static function setPreference (User $user, $key, $value) { + if (!PartKeepr::getEM()->contains($user)) { + throw new EntityNotPersistantException(); + } + + $dql = "SELECT up FROM PartKeepr\UserPreference\UserPreference up WHERE up.user = :user AND "; + $dql .= "up.preferenceKey = :key"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", $user); + $query->setParameter("key", $key); + + try { + $userPreference = $query->getSingleResult(); + } catch (\Exception $e) { + $userPreference = new UserPreference(); + $userPreference->setUser($user); + $userPreference->setKey($key); + + PartKeepr::getEM()->persist($userPreference); + } + + $userPreference->setValue($value); + + PartKeepr::getEM()->flush(); + + return $userPreference; + } + + /** + * Returns a specific preference value for the given user + * + * @param User $user The user to retrieve the preference for + * @param string $key The preference key to retrieve + * @return string The preference string + * @throws UserPreferenceNotFoundException Thrown if the preference key was not found + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public static function getPreferenceValue (User $user, $key) { + $userPreference = self::getPreference($user, $key); + + return $userPreference->getValue(); + } + + /** + * Returns all preferences for the given user + * @param User $user The user + * @throws EntityNotPersistantException Thrown if the user entity is not persistent + */ + public static function getPreferences (User $user) { + if (!PartKeepr::getEM()->contains($user)) { + throw new EntityNotPersistantException(); + } + + $dql = "SELECT up FROM PartKeepr\UserPreference\UserPreference up WHERE up.user = :user"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", $user); + + return $query->getResult(); + } + + /** + * Returns a specific preference object for the given user + * + * @param User $user The user to retrieve the preference for + * @param string $key The preference key to retrieve + * @return UserPreference The preference object + * @throws UserPreferenceNotFoundException Thrown if the preference key was not found + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public static function getPreference (User $user, $key) { + if (!PartKeepr::getEM()->contains($user)) { + throw new EntityNotPersistantException(); + } + + $dql = "SELECT up FROM PartKeepr\UserPreference\UserPreference up WHERE up.user = :user AND "; + $dql .= "up.preferenceKey = :key"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", $user); + $query->setParameter("key", $key); + + try { + $up = $query->getSingleResult(); + return $up; + } catch (NoResultException $e) { + throw new UserPreferenceNotFoundException($user, $key); + } + } + + /** + * Removes a specific setting for a specific user. + * + * @param User $user The user to delete the preference for + * @param string $key The key to delete + * @throws EntityNotPersistantException Thrown if the entity is not persistant + */ + public static function deletePreference (User $user, $key) { + if (!PartKeepr::getEM()->contains($user)) { + throw new EntityNotPersistantException(); + } + + $dql = "DELETE FROM PartKeepr\UserPreference\UserPreference up WHERE up.user = :user AND "; + $dql .= "up.preferenceKey = :key"; + + $query = PartKeepr::getEM()->createQuery($dql); + $query->setParameter("user", $user); + $query->setParameter("key", $key); + + $query->execute(); + } + +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/UserPreference/UserPreferenceService.php b/src/backend/PartKeepr/UserPreference/UserPreferenceService.php @@ -0,0 +1,96 @@ +<?php +namespace PartKeepr\UserPreference; + +use PartKeepr\User\User, + PartKeepr\Util\Configuration, + PartKeepr\Service\RestfulService, + PartKeepr\Session\SessionManager, + PartKeepr\Service\Service, + PartKeepr\PartKeepr; + +/** + * Represents the user preference service. This service is implemented as a RestfulService, however, + * only setting and deleting properties is supported, as we don't want to have duplicate values per key. + * + * For convinience, create() and update() perform the exact same function. + * @author felicitus + * + */ +class UserPreferenceService extends Service implements RestfulService { + /** + * Returns the preferences for the current user, or a user specified by user_id (admin only). + * + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::get() + */ + public function get () { + $user = null; + + if ($this->hasParameter("user_id") && SessionManager::getCurrentSession()->getUser()->isAdmin()) { + if ($this->getParameter("user_id") != 0) { + $user = User::loadById($this->getParameter("user_id")); + } + } else { + $user = SessionManager::getCurrentSession()->getUser(); + } + + $aPreferences = array(); + + foreach ($user->getPreferences() as $result) { + $aPreferences[] = $result->serialize(); + } + + return array("data" => $aPreferences); + } + + /** + * Creates or updates a value for a specific key. + * + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::create() + */ + public function create() { + $userPreference = UserPreference::setPreference($this->getUser(), $this->getParameter("key"), $this->getParameter("value")); + + return array("data" => $userPreference->serialize()); + } + + /** + * Creates or updates a value for a specific key. + * + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::update() + */ + public function update () { + return $this->create(); + } + + /** + * Deletes a key-value combination from the database. + * + * (non-PHPdoc) + * @see PartKeepr\Service.RestfulService::destroy() + */ + public function destroy () { + if ($this->hasParameter("user_id") && SessionManager::getCurrentSession()->getUser()->isAdmin()) { + UserPreference::deletePreference(User::loadById($this->getParameter("user_id")), $this->getParameter("key")); + } else { + UserPreference::deletePreference($this->getUser(), $this->getParameter("key")); + } + } + + public function changePassword () { + if (Configuration::getOption("partkeepr.frontend.allow_password_change", true) === false) { + throw new \Exception("Password changing has been disabled on this server"); + } + + if (!$this->getUser()->compareHashedPassword($this->getParameter("oldpassword"))) { + throw new \Exception("Invalid Password"); + } else { + $this->getUser()->setHashedPassword($this->getParameter("newpassword")); + } + + return array("data" => PartKeepr::i18n("Password changed successfully")); + + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/BaseEntity.php b/src/backend/PartKeepr/Util/BaseEntity.php @@ -0,0 +1,116 @@ +<?php +namespace PartKeepr\Util; + +use PartKeepr\Util\Exceptions\EntityNotFoundException, + PartKeepr\PartKeepr; + +/** @MappedSuperclass */ +class BaseEntity { + /** + * @Id @Column(type="integer") + * @GeneratedValue(strategy="AUTO") + * @var unknown_type + */ + private $id; + + /** + * Returns the ID of this object. + * @param none + * @return int The ID of this object + */ + public function getId () { + return $this->id; + } + + /** + * Syncs a given collection with the entity's collection. + * + * This is used for 1:n or m:n relations, where we need to process inserts, updates and deletes for the records. + * + * @param array $sourceArray The array with all records which should be deserialized + * @param \Doctrine\Common\Collections\Collection $collection The collection which contains the existing records + * @param string $entityClass The class name which is used when a new entity needs to be created + */ + public function deserializeChildren (array $sourceArray, \Doctrine\Common\Collections\Collection $collection, $entityClass) { + $deletes = array(); + $inserts = array(); + + /* Round 1: Check if we've got a matching id in both lists. If yes, we know that the record + * should be updated. If no, the record should be appended */ + foreach ($sourceArray as $sourceItem) { + $bFound = false; + foreach ($collection as $item) { + if ($item->getId() == $sourceItem["id"]) { + // Directly update + $item->deserialize($sourceItem); + $bFound = true; + break; + } + } + + if (!$bFound) { + $inserts[] = $sourceItem; + } + } + + /* Round 2: Check for items which are in the collection but not in the sourceArray. */ + foreach ($collection as $targetItem) { + $bFound = false; + foreach ($sourceArray as $item) { + if ($targetItem->getId() == $item["id"]) { + $bFound = true; + break; + } + } + + if (!$bFound) { + $deletes[] = $targetItem; + } + } + + foreach ($inserts as $item) { + $class = new $entityClass; + $class->deserialize($item); + + $collection->add($class); + PartKeepr::getEM()->persist($class); + } + + /* Remove the to-be-deleted items from the collection. Note that we store the instance of the item, + * so we can simply use removeElement. + */ + foreach ($deletes as $item) { + $collection->removeElement($item); + PartKeepr::getEM()->remove($item); + } + } + + /** + * Serializes the children of a specific collection + * @param \Doctrine\Common\Collections\Collection $array The array holding BaseEntities to serialize + */ + public function serializeChildren (\Doctrine\Common\Collections\Collection $array) { + $aData = array(); + $aData["totalCount"] = $array->count(); + $aData["data"] = array(); + + foreach ($array as $item) { + $aData["data"][] = $item->serialize(); + } + + return array("response" => $aData); + } + + /** + * Loads the entity from the database. + * @param integer $id The entity's id + */ + public static function loadById ($id) { + $entity = PartKeepr::getEM()->find(get_called_class(), $id); + + if (!is_object($entity)) { + throw new EntityNotFoundException(get_called_class(), $id); + } + return $entity; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/Configuration.php b/src/backend/PartKeepr/Util/Configuration.php @@ -0,0 +1,92 @@ +<?php +namespace PartKeepr\Util; + +use PartKeepr\PartKeepr; + +/** + * This class manages simple key -> value configurations within the system. + * + * This allows the user to configure certain aspects of the system in a central place. + * + * The convention is to use a dotted format, for example: + * + * flipbeat.cms.layoutrenderer + * + * @author felicitus + */ +class Configuration { + private static $options = array(); + + /** + * Sets the option to value. + * + * @param string $option The option to set + * @param string $value The value to set + */ + public static function setOption ($option, $value) { + Configuration::$options[$option] = $value; + } + + /** + * Returns the value of an option. The developer + * may additionally specify a default value, which + * is returned when no option was found. + * + * @param string $option The option to return + * @param string $default The default value if the option was not found + */ + public static function getOption ($option, $default = false) { + if (!array_key_exists($option, Configuration::$options)) { + return $default; + } + return Configuration::$options[$option]; + } + + /** + * Returns all configuration options + * + * @return array An array with key=>value assignments + */ + public static function getOptions () { + return Configuration::$options; + } + + /** + * Returns a configuration file, based on all configurations. + * + * @param none + * @return string A complete configuration file including namespace and use directives + */ + public static function dumpConfig () { + $config = <<<EOD +<?php +namespace PartKeepr; +use PartKeepr\Util\Configuration; + + +EOD; + foreach (Configuration::$options as $option => $value) { + switch (PartKeepr::getType($value)) { + case "string": + $config .= 'Configuration::setOption("'.$option.'", "'.$value.'");'."\n"; + break; + case "boolean": + $config .= 'Configuration::setOption("'.$option.'", '.($value === true ? 'true' : 'false').');'."\n"; + break; + case "integer": + case "numeric": + $config .= 'Configuration::setOption("'.$option.'", '.intval($value).');'."\n"; + break; + case "float": + $config .= 'Configuration::setOption("'.$option.'", '.floatval($value).');'."\n"; + break; + default: + break; + } + + } + + return $config; + } +} +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/Deserializable.php b/src/backend/PartKeepr/Util/Deserializable.php @@ -0,0 +1,10 @@ +<?php +namespace PartKeepr\Util; + +interface Deserializable { + /** + * Deserializes the entity from an array format + * @param $parameters array The serialized form of the entity to deserialize + */ + public function deserialize (array $parameters); +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/Exceptions/EntityNotFoundException.php b/src/backend/PartKeepr/Util/Exceptions/EntityNotFoundException.php @@ -0,0 +1,17 @@ +<?php +namespace PartKeepr\Util\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** + * Thrown when an entity via loadById() was not found. + */ +class EntityNotFoundException extends SerializableException { + public function __construct ($class, $id) { + parent::__construct( + sprintf( + PartKeepr::i18n("The entity %s with the id %d could not be found"), + $class, $id)); + } +} diff --git a/src/backend/PartKeepr/Util/Exceptions/EntityNotPersistantException.php b/src/backend/PartKeepr/Util/Exceptions/EntityNotPersistantException.php @@ -0,0 +1,14 @@ +<?php +namespace PartKeepr\Util\Exceptions; + +use PartKeepr\Util\SerializableException, + PartKeepr\PartKeepr; + +/** + * Thrown when an entity via loadById() was not found. + */ +class EntityNotPersistantException extends SerializableException { + public function __construct () { + parent::__construct("The entity is not persistant."); + } +} diff --git a/src/backend/PartKeepr/Util/Exceptions/OutOfRangeException.php b/src/backend/PartKeepr/Util/Exceptions/OutOfRangeException.php @@ -0,0 +1,6 @@ +<?php +namespace PartKeepr\Util\Exceptions; + +use PartKeepr\Util\SerializableException; + +class OutOfRangeException extends SerializableException {} diff --git a/src/backend/PartKeepr/Util/OS/OperatingSystem.php b/src/backend/PartKeepr/Util/OS/OperatingSystem.php @@ -0,0 +1,94 @@ +<?php +namespace PartKeepr\Util\OS; + +class OperatingSystem { + /** + * Returns the platform name the system is running on. + * + * Typical return values are: "Linux", "FreeBSD", "Darwin" (Mac OSX), + * "Windows". + */ + public function getPlatform () { + if (function_exists("posix_uname")) { + $data = posix_uname(); + + if (array_key_exists("sysname", $data)) { + return $data["sysname"]; + } + } + + if (\PHP_OS == "WINNT") { + return "Windows"; + } + + return "unknown"; + } + + /** + * Returns the distribution + * @return string string + */ + public function getRelease () { + switch (strtolower($this->getPlatform())) { + case "freebsd": + /** + * Unfortunately, there's no text file on FreeBSD which tells us the release + * number. Thus, we hope that "release" within posix_uname() is defined. + */ + if (function_exists("posix_uname")) { + $data = posix_uname(); + + if (array_key_exists("release", $data)) { + return $data["release"]; + } + } + break; + case "darwin": + /** + * Mac stores its version number in a public readable plist file, which + * is in XML format. + */ + $document = new \DomDocument(); + $document->load("/System/Library/CoreServices/SystemVersion.plist"); + $xpath = new \DOMXPath($document); + $entries = $xpath->query("/plist/dict/*"); + + $previous = ""; + foreach ($entries as $entry) { + if (strpos($previous, "ProductVersion") !== false) { + return $entry->textContent; + } + $previous = $entry->textContent; + } + break; + case "linux": + return $this->getLinuxDistribution(); + break; + default: + break; + } + + return "unknown"; + } + + /** + * Tries to detect the distribution. + * + * Currently, we only execute lsb_release to find out the version number. + * As I don't have any other distributions at hand to test with, I rely + * on user feedback which distributions don't have lsb_release. + */ + public function getLinuxDistribution () { + /* Try executing lsb_release */ + $release = @exec('lsb_release -d -s', $void, $retval); + + if ($retval === 0 && $release !== "") + { + return $release; + } + + //@todo we need better handling here + return "unknown"; + } + +} diff --git a/src/backend/PartKeepr/Util/Serializable.php b/src/backend/PartKeepr/Util/Serializable.php @@ -0,0 +1,11 @@ +<?php +namespace PartKeepr\Util; + +interface Serializable { + /** + * Serializes the entity into an array format, which in turn can + * be used by json_encode. + * @return array The serialized form of the entity + */ + public function serialize (); +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/SerializableException.php b/src/backend/PartKeepr/Util/SerializableException.php @@ -0,0 +1,60 @@ +<?php +namespace PartKeepr\Util; + +class SerializableException extends \Exception { + protected $detailMessage = "No detail message has been entered."; + + /* @todo: stub */ + public function getDetail () { + return $this->detailMessage; + } + + public function setDetail ($message) { + $this->detailMessage = $message; + } + + public function serialize () { + return array( + "message" => $this->getMessage(), + "detail" => $this->getDetail(), + "exception" => get_class($this), + "code" => $this->getCode() + //"backtrace" => $this->getFormattedTrace() + ); + } + + public function getFormattedTrace () { + $items = $this->getTrace(); + + $message = ""; + + $args = array(); + + foreach ($items as $id => $item) { + foreach ($item["args"] as $itemData) { + switch (gettype($itemData)) { + case "object": + if (method_exists($itemData, "__toString")) { + $args[] = get_class($itemData) . "(".$itemData->__toString().")"; + } else { + $args[] = get_class($itemData); + } + break; + case "array": + $args[] = "array"; + break; + default: + $args[] = $itemData; + break; + } + } + + $message .= $item["file"].":".$item["line"]."\n"; + $message .= $item["function"] ."(".implode(",", $args).")"."\n\n"; + } + + return $message; + } + +} +?>+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/Singleton.php b/src/backend/PartKeepr/Util/Singleton.php @@ -0,0 +1,22 @@ +<?php +namespace PartKeepr\Util; + +abstract class Singleton { + static $instance = null; + + private function __construct () { + + } + + /** + * Returns an instance of the current singleton + * @return $this + */ + public static function getInstance () { + if (!static::$instance instanceof static) { + static::$instance = new static; + } + + return static::$instance; + } +}+ \ No newline at end of file diff --git a/src/backend/PartKeepr/Util/UtilService.php b/src/backend/PartKeepr/Util/UtilService.php @@ -0,0 +1,13 @@ +<?php +namespace PartKeepr\Util; + +use PartKeepr\Service\AnonService; + +class UtilService extends AnonService { + public function clearCache () { + apc_clear_cache(); + apc_clear_cache("user"); + + return array("status" => "ok"); + } +}+ \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Auth/AuthService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Auth/AuthService.php @@ -1,52 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Auth; - -use de\RaumZeitLabor\PartKeepr\Service\AnonService, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\User\UserManager, - de\RaumZeitLabor\PartKeepr\User\Exceptions\InvalidLoginDataException, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class AuthService extends AnonService { - /** - * Logs in the given user. If the login was successful, - * a session is automatically started. - * - * @throws InvalidLoginDataException - */ - public function login () { - $this->requireParameter("username"); - $this->requireParameter("password"); - - /* Build a temporary user */ - $user = new User; - $user->setRawUsername($this->getParameter("username")); - $user->setHashedPassword($this->getParameter("password")); - - $authenticatedUser = UserManager::getInstance()->authenticate($user); - - if ($authenticatedUser !== false) { - /* Start Session */ - $session = SessionManager::getInstance()->startSession($authenticatedUser); - - $aPreferences = array(); - - foreach ($session->getUser()->getPreferences() as $result) { - $aPreferences[] = $result->serialize(); - } - - return array( - "sessionid" => $session->getSessionID(), - "username" => $this->getParameter("username"), - "admin" => $session->getUser()->isAdmin(), - "userPreferences" => array( - "response" => array( - "data" => $aPreferences - ))); - } else { - throw new InvalidLoginDataException(); - } - - - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategory.php b/src/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategory.php @@ -1,202 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Category; - -use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; -use de\RaumZeitLabor\PartKeepr\Util\Serializable; -use DoctrineExtensions\NestedSet\Node; - -/** - * @MappedSuperclass - * @Table(indexes={@index(columns={"lft"}),@index(columns={"rgt"})}) - * - * Represents an abstract category. This class isn't directly usable; you need to inherit it to take advantage of - * the AbstractCategoryManager. - * - * If you are interested on how NestedSets work, please read http://en.wikipedia.org/wiki/Nested_set_model - */ -class AbstractCategory extends BaseEntity implements Node, Serializable { - /** - * The "left" property of the nested set - * @Column(type="integer") - * @var integer - */ - private $lft; - - /** - * The "right" property of the nested set - * @Column(type="integer") - * @var integer - */ - private $rgt; - - /** - * The name of the category - * @Column(length=128) - * @var string - */ - private $name; - - /** - * The description of the category - * @Column(type="text",nullable=true) - * @var string - */ - private $description; - - /** - * Holds the parent node ID. Note that this - * is not a persistant value, but rather calculated - * or set on the fly. - * @var int - */ - private $parent; - - /** - * Holds the category path. - * - * @Column(type="text",nullable=true) - * - * @var string - */ - private $categoryPath; - - /** - * Sets the name of this category - * @param string $name The name to set - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of this category - * @return string The category name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the parent for this category. - * - * @param int $id The parent node - */ - public function setParent ($id) { - $this->parent = $id; - } - - /** - * Returns the parent node for this node. - * @return int The parent node - */ - public function getParent () { - return $this->parent; - } - - /** - * Sets the description for this category - * @param string $description The description of this category - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description of this category - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * Returns the "left" value of the nested set. - * - * @return int The left value - * - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::getLeftValue() - */ - public function getLeftValue() { - return $this->lft; - } - - /** - * Sets the "left" value. - * - * @param $lft integer The left value - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::setLeftValue() - */ - public function setLeftValue($lft) { - $this->lft = $lft; - } - - /** - * Returns the "right" value of the nested set. - * - * @return int The right value - * - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::getRightValue() - */ - public function getRightValue() { - return $this->rgt; - } - - /** - * Sets the "right" value of the nested set - * - * @param $rgt int The right value - * - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::setRightValue() - */ - public function setRightValue($rgt) { - $this->rgt = $rgt; - } - - /** - * Serializes the entity. - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription() - ); - } - - /** - * Returns a string representation of the current node. - * - * @return string The node name - * - * (non-PHPdoc) - * @see DoctrineExtensions\NestedSet.Node::__toString() - */ - public function __toString () { - return $this->getName(); - } - - /** - * Retrieves the category path - * - * @return string The category path - */ - public function getCategoryPath () { - return $this->categoryPath; - } - - /** - * Sets the category path. - * - * THIS IS ONLY TO BE CALLED FROM THE CATEGORYMANAGER! DON'T MESS WITH IT! - * - * @param string $categoryPath - */ - public function setCategoryPath ($categoryPath) { - $this->categoryPath = $categoryPath; - } - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategoryManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategoryManager.php @@ -1,222 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Category; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Category\Category, - de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\Category\Exceptions\CategoryNotFoundException, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Configuration, - DoctrineExtensions\NestedSet\Manager, - DoctrineExtensions\NestedSet\Config, - DoctrineExtensions\NestedSet\NodeWrapper; - -abstract class AbstractCategoryManager extends Singleton { - /** - * Holds the node manager - * @var object The node manager - */ - private $nodeManager; - - /** - * Holds the FQCN of the target entity - * @var de\RaumZeitLabor\PartKeepr\Category\AbstractCategory - */ - protected $categoryClass = "de\RaumZeitLabor\PartKeepr\Category\AbstractCategory"; - - /** - * Returns the node manager. Creates it if it doesn't exist. - * @todo Can this method be made private? - * @return Manager The node manager - */ - public function getNodeManager () { - if (!$this->nodeManager) { - $config = new Config(PartKeepr::getEM(), $this->categoryClass); - - $this->nodeManager = new Manager($config); - } - - return $this->nodeManager; - } - - /** - * Returns the child node id's for a given node id. - * @param integer $id The ID for which to retrieve the child nodes - * @return array An array of the children id's - * @todo Refactor this method name to indicate that it operates on IDs only. - */ - public function getChildNodes ($id) { - $category = $this->getCategory($id); - - $aData = array(); - - foreach ($category->getDescendants() as $cat) { - $aData[] = $cat->getNode()->getId(); - } - return $aData; - } - - /** - * Returns all categories. - * @return The category tree - */ - public function getAllCategories () { - return $this->getNodeManager()->fetchTree(1); - } - - /** - * Ensures that the root node exists. If not, this method creates it. - */ - public function ensureRootExists () { - /* Check if the root node exists */ - $rootNode = $this->getNodeManager()->fetchTree(1); - - if ($rootNode === null) { - $this->createRootNode(); - } - } - - /** - * Returns the root node for the category tree. - * @return The category root node - */ - public function getRootNode () { - return $this->getNodeManager()->fetchTree(1); - } - - /** - * Create the root node for the category tree. - */ - public function createRootNode () { - $rootNode = new $this->categoryClass(); - $rootNode->setName("Root Category"); - $rootNode->setDescription(""); - - $this->getNodeManager()->createRoot($rootNode); - } - - /** - * Adds a given category. - * @param Category $category The category to add to the tree - * @return Category the added category - */ - public function addCategory (AbstractCategory $category) { - $parent = $category->getParent(); - - if ($parent == 0) { - $parent = $this->getRootNode(); - } else { - $parent = PartKeepr::getEM()->find($this->categoryClass, $parent); - $parent = new NodeWrapper($parent, $this->getNodeManager()); - } - - $node = $parent->addChild($category); - - // Force category path update - $this->updateCategoryPaths($node); - - // Flush the category path changes - PartKeepr::getEM()->flush(); - - return $node; - } - - /** - * Deletes the given category ID. - * @param $id int The category id to delete - * @throws CategoryNotFoundException If the category wasn't found - */ - public function deleteCategory ($id) { - $this->getCategory($id)->delete(); - } - - /** - * Returns the category with the given ID. - * @param int $id The category id - * @throws CategoryNotFoundException If the category wasn't found - */ - public function getCategory ($id) { - $category = $this->loadCategoryById($id); - - return new NodeWrapper($category, $this->getNodeManager()); - } - - /** - * Returns the overall category count currently existing. - * @return int The amount of categories in the database - */ - public function getCategoryCount () { - $dql = "SELECT COUNT(c.id) FROM ".$this->categoryClass." c"; - - return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); - } - - /** - * Updates the category paths for a given node and all children. - * - * This method is usually called whenever a category is moved. - * - * @param NodeWrapper $startNode The node to start updating at - */ - public function updateCategoryPaths (NodeWrapper $startNode) { - $pathSeparator = Configuration::getOption("partkeepr.category.path_separator", " ➤ "); - - $startNode->getNode()->setCategoryPath($startNode->getPath($pathSeparator, true)); - - foreach ($startNode->getChildren() as $child) { - $this->updateCategoryPaths($child); - } - } - - /** - * Creates a category tree by an array of category names - * @param array $aCategoryNames - * @param Category A category where to start searching at - */ - public function createCategoryTreeByArray ($aCategoryNames, NodeWrapper $rootNode = null) { - if (count($aCategoryNames) == 0) { - return false; - } - - $categoryName = array_shift($aCategoryNames); - - if ($rootNode === null) { - $rootNode = $this->getRootNode(); - } - - $bFound = false; - foreach ($rootNode->getChildren() as $child) { - if ($child->getNode()->getName() == $categoryName) { - $bFound = true; - $category = $child->getNode(); - break; - } - } - - if ($bFound === false) { - $category = new $this->categoryClass(); - $category->setName($categoryName); - $category->setDescription(""); - $category->setParent($rootNode->getId()); - $this->addCategory($category); - } - - $result = $this->createCategoryTreeByArray($aCategoryNames,new NodeWrapper($category, $this->getNodeManager())); - - if ($result === false) { - return $category; - } else { - return $result; - } - } - - /** - * Loads a category by id - * @param string $id - */ - protected function loadCategoryById($id) { - $class = $this->categoryClass; - - return $class::loadById($id); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategoryService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Category/AbstractCategoryService.php @@ -1,145 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Category; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, - DoctrineExtensions\NestedSet\NodeWrapper; - - -abstract class AbstractCategoryService extends Service { - protected $categoryManagerClass = "de\RaumZeitLabor\PartKeepr\Category\AbstractCategoryManager"; - protected $categoryClass = "de\RaumZeitLabor\PartKeepr\Category\AbstractCategory"; - - /** - * Returns all categories found in the system. - * @return array A serialized tree - */ - public function getCategories () { - $categories = $this->getCategoryManager()->getAllCategories( - $this->getParameter("parent", 0)); - - return $this->serializeTree($categories); - } - - /** - * Moves the given category from one to another category. - */ - public function moveCategory () { - $this->requireParameter("category"); - $this->requireParameter("target"); - - $category = $this->getCategoryManager()->getCategory($this->getParameter("category")); - - if (intval($this->getParameter("target", 0)) !== 0) { - - $parent = $this->getCategoryManager()->getCategory($this->getParameter("target")); - - $category->moveAsLastChildOf($parent); - $this->getCategoryManager()->updateCategoryPaths($category); - - } - } - - /** - * Deletes the given category. - */ - public function deleteCategory () { - $this->requireParameter("id"); - - $this->getCategoryManager()->deleteCategory($this->getParameter("id")); - - return array("id" => $this->getParameter("id")); - } - - /** - * Updates the given category. - */ - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - - $category = $this->getCategoryManager()->getCategory($this->getParameter("id")); - - $category->getNode()->setName($this->getParameter("name")); - $category->getNode()->setDescription($this->getParameter("description", "")); - - PartKeepr::getEM()->persist($category->getNode()); - - $this->getCategoryManager()->updateCategoryPaths($category); - - return array("data" => $this->serializeCategory($category)); - } - - public function create () { - $this->requireParameter("name"); - $this->requireParameter("parent"); - - $category = new $this->categoryClass; - $category->setName($this->getParameter("name")); - $category->setDescription($this->getParameter("description", "")); - $category->setParent($this->getParameter("parent")); - - $category = $this->getCategoryManager()->addCategory($category); - - $this->getCategoryManager()->updateCategoryPaths($category); - - return array("data" => $this->serializeCategory($category)); - } - - public function destroy () { - return $this->deleteCategory(); - } - - private function serializeCategory ($category) { - $data = $category->getNode()->serialize(); - - if ($category->getParent() !== null) { - $data["parent"] = $category->getParent()->getNode()->getId(); - $data["parentName"] = $category->getParent()->getNode()->getName(); - } - - return $data; - } - - /** - * Returns all categories - */ - public function getAllCategories () { - return $this->serializeTree($this->getCategoryManager()->getAllCategories()); - } - - /** - * Serializes the given NodeWrapper as array including all children. - * @param NodeWrapper $node The category nodewrapper to serialize - * @throws \Exception - */ - public function serializeTree (NodeWrapper $node = null) { - if ($node == null) { - throw new \Exception("Node must not be null!"); - } - - $aData = $node->getNode()->serialize(); - - $aData["children"] = array(); - - if (count($node->getChildren()) == 0) { - $aData["leaf"] = true; - } else { - $aData["expanded"] = true; - } - - foreach ($node->getChildren() as $child) { - $aData["children"][] = $this->serializeTree($child); - - } - - return $aData; - } - - public function getCategoryManager () { - $categoryManager = $this->categoryManagerClass; - - return $categoryManager::getInstance(); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Category/Exceptions/CategoryNotFoundException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Category/Exceptions/CategoryNotFoundException.php @@ -1,15 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Category\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Thrown when the requested category was not found. - */ -class CategoryNotFoundException extends SerializableException { - public function __construct ($id) { - parent::__construct(sprintf(PartKeepr::i18n("Category %d not found."), $id)); - } -} -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/CronLogger/CronLogger.php b/src/backend/de/RaumZeitLabor/PartKeepr/CronLogger/CronLogger.php @@ -1,58 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\CronLogger; - -use de\RaumZeitLabor\PartKeepr\UploadedFile\UploadedFile, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\Deserializable; - -/** - * Holds a project attachment - * @Entity - **/ -class CronLogger extends BaseEntity { - /** - * @Column(type="datetime") - * @var \DateTime - */ - private $lastRunDate; - - /** - * @Column(type="string") - * @var string - */ - private $cronjob; - - /** - * Sets the last run date and time for this entry - * @param \DateTime $date The date and time - */ - public function setLastRunDate (\DateTime $date) { - $this->lastRunDate = $date; - } - - /** - * Returns the date and time for this entry - * - * @return \DateTime the date and time for this entry - */ - public function getLastRunDate () { - return $this->lastRunDate; - } - - /** - * Sets the cronjob for this entry - * @param string $cronjob the title for this entry - */ - public function setCronjob ($cronjob) { - $this->cronjob = $cronjob; - } - - /** - * Returns the cronjob for this entry - * @return string the title - */ - public function getCronjob () { - return $this->cronjob; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/CronLogger/CronLoggerManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/CronLogger/CronLoggerManager.php @@ -1,86 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\CronLogger; - -use de\RaumZeitLabor\PartKeepr\Manager\AbstractManager, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class CronLoggerManager extends AbstractManager { - /** - * Returns the FQCN for the target entity to operate on. - * @return string The FQCN, e.g. de\RaumZeitLabor\PartKeepr\Part - */ - public function getEntityName () { - return 'de\RaumZeitLabor\PartKeepr\CronLogger\CronLogger'; - } - - /** - * 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"; - } - - /** - * Marks a specific cronjob as ran - * @param string $cronjob The name of the cronjob - */ - public function markCronRun ($cronjob) { - $dql = "SELECT c FROM de\RaumZeitLabor\PartKeepr\CronLogger\CronLogger c WHERE c.cronjob = :cronjob"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("cronjob", $cronjob); - - try { - $result = $query->getSingleResult(); - } catch (\Exception $e) { - $result = new CronLogger(); - $result->setCronjob($cronjob); - PartKeepr::getEM()->persist($result); - } - - $result->setLastRunDate(new \DateTime()); - - PartKeepr::getEM()->flush(); - } - - /** - * Returns a list of all inactive cronjobs - * - * @param none - * @return array A string of cronjob names which aren't running - */ - public function getInactiveCronjobs () { - $dql = "SELECT c.cronjob FROM de\RaumZeitLabor\PartKeepr\CronLogger\CronLogger c WHERE c.cronjob = :cronjob"; - $dql .= " AND c.lastRunDate > :date"; - - $query = PartKeepr::getEM()->createQuery($dql); - - $date = new \DateTime(); - $date->sub(new \DateInterval('P1D')); - $query->setParameter("date", $date); - - $failedCronjobs = array(); - - foreach (PartKeepr::getRequiredCronjobs() as $cronjob) { - $query->setParameter("cronjob", $cronjob); - - try { - $query->getSingleResult(); - } catch (\Exception $e) { - $failedCronjobs[] = $cronjob; - } - - } - - return $failedCronjobs; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Distributor/Distributor.php b/src/backend/de/RaumZeitLabor/PartKeepr/Distributor/Distributor.php @@ -1,231 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Distributor; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Represents a distributor - * @Entity **/ -class Distributor extends BaseEntity implements Serializable, Deserializable { - /** - * Holds the name of the distributor - * @Column(type="string",unique=true) - * @var string - */ - private $name; - - /** - * Holds the address of the distributor - * @Column(type="text",nullable=true) - * @var string - */ - private $address; - - /** - * Holds the URL of the distributor - * @Column(type="string",nullable=true) - * @var string - */ - private $url; - - /** - * Holds the phone number of the distributor - * @Column(type="string",nullable=true) - * @var string - */ - private $phone; - - /** - * Holds the fax number of the distributor - * @Column(type="string",nullable=true) - * @var string - */ - private $fax; - - /** - * Holds the email of the distributor - * @Column(type="string",nullable=true) - * @var string - */ - private $email; - - /** - * Holds a comment for the distributor - * @Column(type="text",nullable=true) - * @var string - */ - private $comment; - - /** - * Sets the name for the distributor - * - * @param string $name The distributor's name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of the distributor - * @return string The distributor's name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the address of this distributor - * - * @param string $address The address of the distributor - */ - public function setAddress ($address) { - $this->address = $address; - } - - /** - * Returns the address of this distributor - * @return string The address of this distributor - */ - public function getAddress () { - return $this->address; - } - - /** - * Sets the phone number for this distributor - * - * @param string $phone The phone number of this distributor - */ - public function setPhone ($phone) { - $this->phone = $phone; - } - - /** - * Returns the phone number of this distributor - * @return string The phone number - */ - public function getPhone () { - return $this->phone; - } - - /** - * Sets the fax number for this distributor - * - * @param string $fax The fax number - */ - public function setFax ($fax) { - $this->fax = $fax; - } - - /** - * Returns the fax number for this distributor - * - * @return string $fax The fax number - */ - public function getFax () { - return $this->fax; - } - - /** - * Sets the comment for this distributor - * - * @param string $comment The comment for this distributor - */ - public function setComment ($comment) { - $this->comment = $comment; - } - - /** - * Returns the comment for this distributor - * - * @return string The comment - */ - public function getComment () { - return $this->comment; - } - - /** - * Sets the email for this distributor - * - * @param string $email The email for this distributor - */ - public function setEmail ($email) { - $this->email = $email; - } - - /** - * Returns the email for this distributor - * @return string The email - */ - public function getEmail () { - return $this->email; - } - - /** - * Sets the URL for this distributor - * - * @param string $url The URL for this distributor - */ - public function setURL ($url) { - $this->url = $url; - } - - /** - * Returns the URL for this distributor - * @return string The URL - */ - public function getURL () { - return $this->url; - } - - /** - * Returns the distributor in serialized form. - * @return array The serialized distributor - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "url" => $this->getURL(), - "address" => $this->getAddress(), - "email" => $this->getEmail(), - "comment" => $this->getComment(), - "phone" => $this->getPhone(), - "fax" => $this->getFax() - ); - } - - /** - * Deserializes the distributor - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "url": - $this->setURL($value); - break; - case "comment": - $this->setComment($value); - break; - case "fax": - $this->setFax($value); - break; - case "phone": - $this->setPhone($value); - break; - case "email": - $this->setEmail($value); - break; - case "address": - $this->setAddress($value); - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Distributor/DistributorManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Distributor/DistributorManager.php @@ -1,107 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Distributor; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Distributor\Distributor, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, - de\RaumZeitLabor\PartKeepr\Distributor\Exceptions\DistributorNotFoundException; - -class DistributorManager extends Singleton { - /** - * Returns a list of distributors. - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter A string to filter the distributor's name by, default empty - */ - public function getDistributors ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st.id, st.name, st.url, st.email, st.comment, st.address")->from("de\RaumZeitLabor\PartKeepr\Distributor\Distributor","st"); - - if ($filter != "") { - $qb = $qb->where("LOWER(st.name) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\Distributor\Distributor","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Returns a distributor by ID. - * - * @param int $id The distributor id - * @return Distributor The distributor - * @throws EntityNotFoundException If no distributor with the ID was found - */ - public function getDistributor ($id) { - return Distributor::loadById($id); - } - - /** - * Creates a new distributor with the given name. - * @param string $name The name of the distributor - * @return Distributor The new distributor object - */ - public function addDistributor ($name) { - $distributor = new Distributor(); - $distributor->setName($name); - - PartKeepr::getEM()->persist($distributor); - PartKeepr::getEM()->flush(); - - return $distributor; - } - - /** - * Deletes a distributor by id - * - * @param int $id The ID of the distributor to delete - */ - public function deleteDistributor ($id) { - $distributor = $this->getDistributor($id); - - PartKeepr::getEM()->remove($distributor); - PartKeepr::getEM()->flush(); - } - - /** - * Retrieves a distributor by its name. - * - * @param string $name The name of the distributor to retrieve - * @throws Doctrine\ORM\NoResultException If the distributor was not found - */ - public function getDistributorByName ($name) { - $dql = "SELECT d FROM de\RaumZeitLabor\PartKeepr\Distributor\Distributor d WHERE d.name = :name"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $name); - - return $query->getSingleResult(); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Distributor/DistributorService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Distributor/DistributorService.php @@ -1,82 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Distributor; -use de\RaumZeitLabor\PartKeepr\Service\RestfulService; - -use de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class DistributorService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return array("data" => DistributorManager::getInstance()->getDistributor($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "name", - "direction" => "ASC"); - } - return DistributorManager::getInstance()->getDistributors( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $this->requireParameter("name"); - - $distributor = new Distributor; - $distributor->deserialize($this->getParameters()); - - PartKeepr::getEM()->persist($distributor); - PartKeepr::getEM()->flush(); - - return array("data" => $distributor->serialize()); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - - $distributor = Distributor::loadById($this->getParameter("id")); - $distributor->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $distributor->serialize()); - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - DistributorManager::getInstance()->deleteDistributor($this->getParameter("id")); - - return array("data" => null); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php b/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/Footprint.php @@ -1,192 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Footprint; -use de\RaumZeitLabor\PartKeepr\Util\Deserializable; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable; -use de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory; -use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; - -/** @Entity */ - -class Footprint extends BaseEntity implements Serializable, Deserializable { - /** - * Holds the footprint name - * @Column(length=64,unique=true) - * @var string - */ - private $name; - - /** - * Holds the footprint description - * @Column(type="text",nullable=true) - * @var string - */ - private $description; - - /** - * The category of the footprint - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory") - * @var Category - */ - private $category; - - /** - * Holds the footprint image - * @OneToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage",mappedBy="footprint",cascade={"persist", "remove"}) - * @var FootprintImage - */ - private $image; - - /** - * Holds the footprint attachments - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment",mappedBy="footprint",cascade={"persist", "remove"}) - * @var FootprintAttachment - */ - private $attachments; - - /** - * Constructs a new Footprint entity - */ - public function __construct () { - $this->attachments = new \Doctrine\Common\Collections\ArrayCollection(); - } - - /** - * Sets the name of this footprint - * - * @param string $name The footprint name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of this footprint - * @return string The name of this footprint - */ - public function getName () { - return $this->name; - } - - /** - * Sets the description of this footprint - * @param string $description The description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description of this footprint - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * Sets the category for this footprint - * @param \de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory $category The category - */ - public function setCategory (FootprintCategory $category) { - $this->category = $category; - } - - /** - * Returns the category of this footprint - * @return FootprintCategory The footprint category - */ - public function getCategory () { - return $this->category; - } - - /** - * Sets the footprint image - * @param FootprintImage $image The footprint image - */ - public function setImage (FootprintImage $image) { - $this->image = $image; - $image->setFootprint($this); - } - - /** - * Returns the footprint image - * @return FootprintImage The footprint image - */ - public function getImage () { - return $this->image; - } - - /** - * Returns the attachments for this footprint - * @return ArrayCollection The attachments - */ - public function getAttachments () { - return $this->attachments; - } - - /** - * Serializes the footprint - * @return array the serialized footprint - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription(), - "image_id" => is_object($this->getImage()) ? $this->getImage()->getId() : null, - "category" => is_object($this->getCategory()) ? $this->getCategory()->getId() : null, - "attachments" => $this->serializeChildren($this->getAttachments()) - ); - } - - /** - * Deserializes the footprint - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "description": - $this->setDescription($value); - break; - case "image_id": - if ($value == "") { - echo "/** Breaking because of empty value */"; - break; } - - try { - $image = FootprintImage::loadById($value); - $this->setImage($image); - } catch (\Exception $e) { - if ($this->getImage()) { - // Image was not found, maybe a temporary image? - $this->getImage()->replaceFromTemporaryFile($value); - } else { - $image = FootprintImage::createFromTemporaryFile($value); - $this->setImage($image); - } - } - - break; - case "category": - try { - $category = FootprintCategory::loadById($value); - $this->setCategory($category); - } catch (\Exception $e) { - // Category was not found, do not change category. - } - break; - case "attachments": - $this->deserializeChildren($value, $this->getAttachments(), "de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment"); - foreach ($this->getAttachments() as $attachment) { - $attachment->setFootprint($this); - } - break; - } - } - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintAttachment.php b/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintAttachment.php @@ -1,101 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Footprint; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\UploadedFile\UploadedFile; - -/** - * Holds a footprint attachment - * @Entity - **/ -class FootprintAttachment extends UploadedFile implements Serializable, Deserializable { - /** - * The description of this attachment - * @Column(type="text") - * @var string - */ - private $description; - - /** - * Creates a new footprint attachment - */ - public function __construct () { - parent::__construct(); - $this->setType("FootprintAttachment"); - } - /** - * The footprint object - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\Footprint") - * @var Footprint - */ - private $footprint = null; - - /** - * Sets the footprint - * @param Footprint $footprint The footprint to set - */ - public function setFootprint (Footprint $footprint) { - $this->footprint = $footprint; - } - - /** - * Returns the footprint - * @return Footprint the footprint - */ - public function getFootprint () { - return $this->footprint; - } - - /** - * Sets the description for this attachment - * @param string $description The attachment description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description for this attachment - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * - * Serializes this footprint attachment - * @return array The serialized footprint attachment - */ - public function serialize () { - return array( - "id" => $this->getId(), - "footprint_id" => $this->getFootprint()->getId(), - "originalFilename" => $this->getOriginalFilename(), - "mimetype" => $this->getMimetype(), - "extension" => $this->getExtension(), - "size" => $this->getSize(), - "description" => $this->getDescription()); - } - - /** - * Deserializes the footprint attachment - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - if (array_key_exists("id", $parameters)) { - if (substr($parameters["id"], 0, 4) === "TMP:") { - $this->replaceFromTemporaryFile($parameters["id"]); - } - } - - foreach ($parameters as $key => $value) { - switch ($key) { - case "description": - $this->setDescription($value); - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintImage.php b/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintImage.php @@ -1,50 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Footprint; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Image\Image; - -/** - * Holds a footprint image - * @Entity - **/ -class FootprintImage extends Image implements Serializable { - /** - * The footprint object - * @OneToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\Footprint",inversedBy="image") - * @var Footprint - */ - private $footprint = null; - - /** - * Creates a new IC logo instance - */ - public function __construct () { - parent::__construct(Image::IMAGE_FOOTPRINT); - } - - /** - * Sets the footprint - * @param Footprint $footprint The footprint to set - */ - public function setFootprint (Footprint $footprint) { - $this->footprint = $footprint; - } - - /** - * Returns the footprint - * @return Footprint the footprint - */ - public function getFootprint () { - return $this->footprint; - } - - /** - * - * Serializes this ic logo - * @return array The serialized ic logo - */ - public function serialize () { - return array("id" => $this->getId(), "footprint_id" => $this->getFootprint()->getId()); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintManager.php @@ -1,158 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Footprint; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotFoundException; - -class FootprintManager extends Singleton { - /** - * Returns a list of footprints. - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter A string to filter the footprint's name by, default empty - */ - public function getFootprints ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("f.id, f.name, f.description, im.id AS image_id, ca.id AS category")->from("de\RaumZeitLabor\PartKeepr\Footprint\Footprint","f") - ->leftJoin("f.image", "im") - ->leftJoin("f.category", "ca"); - - if ($filter != "") { - $qb = $qb->where("LOWER(f.name) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("f.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(f.id)")->from("de\RaumZeitLabor\PartKeepr\Footprint\Footprint","f")->leftJoin("f.image", "im"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(f.name) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Creates a new footprint - * - * @param string $footprint The footprint's name - * @throws \de\RaumZeitLabor\PartKeepr\Util\SerializableException - * @throws PDOException - */ - public function addFootprint ($name) { - $fp = new Footprint(); - $fp->setName($name); - - // @todo Port the UniqueEntityValidator from Symfony2 to here. - try { - PartKeepr::getEM()->persist($fp); - PartKeepr::getEM()->flush(); - } catch (\PDOException $e) { - if ($e->getCode() == "23000") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Footprint %s already exists!"), $name)); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to add the footprint %s, but a footprint with the same name already exists."), $name)); - - throw $exception; - } else { - throw $e; - } - } - - return $fp; - } - - /** - * Deletes the footprint with the given id. - * - * @param int $id The footprint id to delete - * @throws \de\RaumZeitLabor\PartKeepr\Util\SerializableException - */ - public function deleteFootprint ($id) { - $footprint = Footprint::loadById($id); - - try { - PartKeepr::getEM()->remove($footprint); - PartKeepr::getEM()->flush(); - } catch (\PDOException $e) { - if ($e->getCode() == "23000") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Footprint %s is in use by some parts!"), $footprint->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the footprint %s, but there are parts which use this footprint."), $footprint->getName())); - - throw $exception; - } - } - } - - /** - * Loads a footprint by id - * @param int $id The footprint id - */ - public function getFootprint ($id) { - return Footprint::loadById($id); - } - - /** - * Finds or creates a footprint by name. - * - * @param mixed $footprint Either the ID or the footprint's name to find - */ - public function getOrCreateFootprint ($footprint) { - try { - $footprint = Footprint::loadById($footprint); - return $footprint; - } catch (EntityNotFoundException $e) {} - - $dql = "SELECT f FROM de\RaumZeitLabor\PartKeepr\Footprint\Footprint f WHERE f.name = :name"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $footprint); - - try { - $footprint = $query->getSingleResult(); - return $footprint; - } catch (\Exception $e) {} - - $fp = new Footprint(); - $fp->setName($footprint); - - PartKeepr::getEM()->persist($fp); - - return $fp; - } - - /** - * Retrieves a distributor by its name. - * - * @param string $name The name of the distributor to retrieve - * @throws Doctrine\ORM\NoResultException If the distributor was not found - */ - public function getFootprintByName ($name) { - $dql = "SELECT fp FROM de\RaumZeitLabor\PartKeepr\Footprint\Footprint fp WHERE fp.name = :name"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $name); - - return $query->getSingleResult(); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Footprint/FootprintService.php @@ -1,96 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Footprint; - -use de\RaumZeitLabor\PartKeepr\TempImage\TempImage, - de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintManager; - -class FootprintService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return array("data" => FootprintManager::getInstance()->getFootprint($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "name", - "direction" => "ASC"); - } - return FootprintManager::getInstance()->getFootprints( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $this->requireParameter("name"); - - $footprint = new Footprint(); - $footprint->deserialize($this->getParameters()); - - PartKeepr::getEM()->persist($footprint); - - PartKeepr::getEM()->flush(); - - return array("data" => $footprint->serialize()); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - $footprint = Footprint::loadById($this->getParameter("id")); - - $footprint->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $footprint->serialize()); - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - FootprintManager::getInstance()->deleteFootprint($this->getParameter("id")); - - return array("data" => null); - } - - public function moveFootprint () { - $this->requireParameter("targetCategory"); - $this->requireParameter("id"); - - $footprint = Footprint::loadById($this->getParameter("id")); - $category = FootprintCategory::loadById($this->getParameter("targetCategory")); - - $footprint->setCategory($category); - - PartKeepr::getEM()->flush(); - } - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/FootprintAttachment/FootprintAttachmentManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/FootprintAttachment/FootprintAttachmentManager.php @@ -1,68 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\FootprintAttachment; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class FootprintAttachmentManager extends Singleton { - /** - * Returns a list of footprint attachments - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter The footprint id - */ - public function getFootprintAttachments ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st")->from("de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment","st") - ->leftJoin('st.footprint', "fp"); - - if ($filter != "") { - $footprint = Footprint::loadById($filter); - $qb = $qb->where("st.footprint = :footprint"); - $qb->setParameter("footprint", $footprint); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("st.footprint = :footprint"); - $totalQueryBuilder->setParameter("footprint", $footprint); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - $aData = array(); - foreach ($result as $item) { - $aData[] = $item->serialize(); - } - return array("data" => $aData, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Returns a footprint attachment by id - * @param int $id The footprint attachment id - */ - public function getFootprintAttachment ($id) { - return FootprintAttachment::loadById($id); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/FootprintAttachment/FootprintAttachmentService.php b/src/backend/de/RaumZeitLabor/PartKeepr/FootprintAttachment/FootprintAttachmentService.php @@ -1,102 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\FootprintAttachment; - -use de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment, - de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class FootprintAttachmentService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return FootprintAttachmentManager::getInstance()->getFootprintAttachment($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"] == "footprint_id") { - if (array_key_exists("value", $item)) { - $filter = $item["value"]; - } - } - } - } - } - return FootprintAttachmentManager::getInstance()->getFootprintAttachments( - $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); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $this->requireParameter("tmp_id"); - $this->requireParameter("footprint_id"); - - $tmpImage = TempUploadedFile::loadById($this->getParameter("tmp_id")); - - $file = new FootprintAttachment(); - - $footprint = Footprint::loadById($this->getParameter("footprint_id")); - - $file->setFootprint($footprint); - $file->replace($tmpImage->getFilename()); - $file->setOriginalFilename($tmpImage->getOriginalFilename()); - $file->setDescription($this->getParameter("description")); - PartKeepr::getEM()->persist($file); - PartKeepr::getEM()->flush(); - - return $file->serialize(); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - $file = FootprintAttachment::loadById($this->getParameter("id")); - - PartKeepr::getEM()->remove($file); - PartKeepr::getEM()->flush(); - - return array("data" => null); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategory.php b/src/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategory.php @@ -1,14 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\FootprintCategory; - -use de\RaumZeitLabor\PartKeepr\Category\AbstractCategory; - -/** - * @Entity - * @Table(indexes={@index(columns={"lft"}),@index(columns={"rgt"})}) - * The entity for our footprint categories - * - */ -class FootprintCategory extends AbstractCategory { - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategoryManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategoryManager.php @@ -1,42 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\FootprintCategory; - -use de\RaumZeitLabor\PartKeepr\Category\AbstractCategoryManager; -use DoctrineExtensions\NestedSet\NodeWrapper; -use de\RaumZeitLabor\PartKeepr\Util\SerializableException; -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -class FootprintCategoryManager extends AbstractCategoryManager { - protected $categoryClass = "de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory"; - - /** - * Deletes the given category ID. - * @param $id int The category id to delete - * @throws CategoryNotFoundException If the category wasn't found - */ - public function deleteCategory ($id) { - $category = $this->getCategory($id); - - try { - - if ($category->hasChildren()) { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains other categories."), $category->getNode()->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains other categories. Please move the categories or delete them first."), $category->getNode()->getName())); - - throw $exception; - } - - parent::deleteCategory($id); - } catch (\PDOException $e) { - if ($e->getCode() == "23000") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains footprints."), $category->getNode()->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains footprints. Please move the footprints to another category."), $category->getNode()->getName())); - - throw $exception; - } else { - throw $e; - } - } - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategoryService.php b/src/backend/de/RaumZeitLabor/PartKeepr/FootprintCategory/FootprintCategoryService.php @@ -1,9 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\FootprintCategory; - -use de\RaumZeitLabor\PartKeepr\Category\AbstractCategoryService; - -class FootprintCategoryService extends AbstractCategoryService { - protected $categoryManagerClass = "de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategoryManager"; - protected $categoryClass = "de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory"; -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/FulltextSearch/FulltextSearch.php b/src/backend/de/RaumZeitLabor/PartKeepr/FulltextSearch/FulltextSearch.php @@ -1,94 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\FulltextSearch; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -abstract class FulltextSearch { - - /** - * Creates a new fulltext search based on the given query. - * - * The query can contain different query strings, separated by space. The query returns only results which contain - * all query strings in any fields. - * - * If the query is "100 ohm", it would only consider entities which have both "100" and "ohm", no matter which field - * the value is in. - * - * @param string $query The query to search for - */ - public function __construct ($query) { - $this->query = explode(" ", $query); - } - - /** - * Fires the query and returns the results. - * - * @param none - * @return array An array with all IDs which match the query - */ - public function query () { - return $this->fallbackSearch(); - } - - /** - * A fallback search in case no fulltext search engine is available. This directly queries the database, which is - * slow. - */ - protected function fallbackSearch () { - $qb = PartKeepr::getEM()->createQueryBuilder(); - - $qb ->select("q.id") - ->from($this->getEntityName(), "q") - ->where("1=1"); - - $dqlChunks = array(); - - foreach ($this->query as $id => $queryString) { - $partDqlChunks = array(); - foreach ($this->getFields() as $field) { - $partDqlChunks[] = "LOWER(q." . $field.") LIKE :filter".$id; - } - - $dqlChunks[] = "(".implode(" OR ", $partDqlChunks).")"; - - $qb->setParameter("filter".$id, "%".str_replace("%", "\\%", strtolower($queryString))."%"); - } - - $qb->andWhere(implode(" AND " ,$dqlChunks)); - - $query = $qb->getQuery(); - - - - $result = $query->getArrayResult(); - - if (count($result) > 0) { - $results = array(); - - foreach ($result as $value) { - $results[] = $value["id"]; - } - - return $results; - } else { - return array(0); - } - } - - /** - * Returns the FQDN name of the entity. This needs to be overridden in child classes. - * - * @param none - * @return string the FQDN of the entity to query, e.g. de\RaumZeitLabor\PartKeepr\Part\Part - */ - abstract protected function getEntityName (); - - /** - * Returns the fields in which the fulltext search should search in. - * - * @param none - * @return array An array of field names, e.g. array("name", "description") - */ - abstract protected function getFields (); - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Image/CachedImage.php b/src/backend/de/RaumZeitLabor/PartKeepr/Image/CachedImage.php @@ -1,99 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Image; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Represtends a cached image. Cached images are used for scale/resize - * operations, so that the resize/scale operation doesn't need to be done - * every time a scaled/resized image is requested. - * - * @Entity - */ -class CachedImage { - /** - * Specifies the ID of the cached image. - * - * @var integer - * @Id - * @Column(type="integer") - * @GeneratedValue(strategy="AUTO") - **/ - private $id; - - /** - * Specifies the ID of the original image - * - * @var integer - * @Column(type="integer") - */ - private $originalId; - - /** - * Specifies the type of the original image. - * - * @var string - * @Column(type="string") - **/ - private $originalType; - - /** - * The cache filename of the image - * - * @var string - * @Column(type="string") - */ - private $cacheFile; - - /** - * Creates a new cache entry for a specific image. - * - * @param Image $image The image to cache - * @param string $cacheFile The file which holds the cached image - */ - public function __construct (Image $image, $cacheFile) { - $this->originalId = (int)$image->getId(); - $this->originalType = $image->getType(); - $this->cacheFile = $cacheFile; - } - - /** - * Returns the cache file - * @return string The cache file including path - */ - public function getCacheFile () { - return $this->cacheFile; - } - - /** - * Removes all caches for a specific image. This is usually called - * when a new version of an image is uploaded. - * - * Automatically calls "flush" on the entity manager. - * - * @param Image $image The image to invalidate - */ - public static function invalidate (Image $image) { - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select(array("c")) - ->from('de\RaumZeitLabor\PartKeepr\Image\CachedImage', 'c') - ->where("c.originalId = :id") - ->andWhere("c.originalType = :type") - ->setParameter("id", $image->getId()) - ->setParameter("type", $image->getType()); - - $query = $qb->getQuery(); - - $bImagesRemoved = false; - - foreach ($query->getResult() as $file) { - unlink($file->getCacheFile()); - PartKeepr::getEM()->remove($file); - $bImagesRemoved = true; - } - - if ($bImagesRemoved) { - PartKeepr::getEM()->flush(); - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Image/Exceptions/InvalidImageTypeException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Image/Exceptions/InvalidImageTypeException.php @@ -1,11 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Image\Exceptions; - -/** - * Thrown if an invalid type was passed - */ -class InvalidImageTypeException extends \Exception { - public function __construct ($type) { - parent::__construct("The image type $type is unknown."); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Image/Image.php b/src/backend/de/RaumZeitLabor/PartKeepr/Image/Image.php @@ -1,254 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Image; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\UploadedFile\UploadedFile, - de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\TempImage\TempImage, - de\RaumZeitLabor\PartKeepr\Image\Exceptions\InvalidImageTypeException; - -/** - * @MappedSuperclass - */ -abstract class Image extends UploadedFile { - const IMAGE_ICLOGO = "iclogo"; - const IMAGE_TEMP = "temp"; - const IMAGE_PART = "part"; - const IMAGE_STORAGELOCATION = "storagelocation"; - const IMAGE_FOOTPRINT = "footprint"; - - /** - * Constructs a new image object. - * - * @param string $type The type for the image, one of the IMAGE_ constants. - */ - public function __construct ($type) { - parent::__construct(); - $this->setType($type); - } - - /** - * Sets the type of the image. Once the type is set, - * it may not be changed later. - * - * @param string $type The type for the image, one of the IMAGE_ constants. - * @throws InvalidImageTypeException - */ - protected function setType ($type) { - switch ($type) { - case Image::IMAGE_ICLOGO: - case Image::IMAGE_TEMP: - case Image::IMAGE_PART: - case Image::IMAGE_FOOTPRINT: - case Image::IMAGE_STORAGELOCATION: - parent::setType($type); - break; - default: - throw new InvalidImageTypeException($type); - } - } - - /** - * Replaces the current image with a new image. - * - * Automatically converts from one format to PNG, - * which is the default when dealing with images - * on the platform. - * - * @param string $path The path to the original image - */ - public function replace ($path) { - parent::replace($path); - - CachedImage::invalidate($this); - } - - /** - * Returns the full image filename including path. - * This is the image where all scale operations take place on. - * - * @param none - * @return string The full image filename including path. - */ - public function getFilename () { - return $this->getFilePath().$this->getPlainFilename().".png"; - } - - /** - * Returns the path to the image. May be overridden by - * subclasses. - * - * @param none - * @return string The path to the image - */ - public function getFilePath () { - return Configuration::getOption( - "partkeepr.images.path", - PartKeepr::getRootDirectory() . "/data/images/") . $this->getType() . "/"; - } - - /** - * Scales the image to a specific width and height - * - * @param int $w The width - * @param int $h The height - * @return string The path to the scaled file - */ - public function scaleTo ($w, $h) { - $this->ensureCachedirExists(); - - $outputFile = Configuration::getOption("partkeepr.images.cache").md5($this->getFilename().$w."x".$h).".png"; - - if (file_exists($outputFile)) { - return $outputFile; - } - $image = new \Imagick(); - $image->readImage($this->getFilename()); - $image->adaptiveResizeImage($w, $h); - $image->writeImage($outputFile); - - $cachedImage = new CachedImage($this, $outputFile); - PartKeepr::getEM()->persist($cachedImage); - - return $outputFile; - } - - /** - * Scales the image to fit exactly within the given size. - * - * This method ensures that no blank space is in the output image, - * and that the output image is exactly the width and height specified. - * - * @param int $w The width - * @param int $h The height - * @return string The path to the scaled file - */ - public function fitWithinExact ($w, $h) { - $this->ensureCachedirExists(); - - $outputFile = Configuration::getOption("partkeepr.images.cache").md5($this->getFilename().$w."x".$h."fwe").".png"; - - if (file_exists($outputFile)) { - return $outputFile; - } - $image = new \Imagick(); - $image->readImage($this->getFilename()); - - $sourceAspectRatio = $image->getImageWidth() / $image->getImageHeight(); - $targetAspectRatio = $w / $h; - - $filter = \Imagick::FILTER_UNDEFINED; - $blur = 1; - - if ($sourceAspectRatio < $targetAspectRatio) { - $image->resizeImage($w, $w / $sourceAspectRatio, $filter, $blur); - } else { - $image->resizeImage($h * $sourceAspectRatio, $h, $filter, $blur); - } - - $offsetX = intval(($image->getImageWidth() - $w)/2); - $offsetY = intval(($image->getImageHeight() - $h)/2); - - $image = $image->getImageRegion($w, $h, $offsetX, $offsetY); - - $image->writeImage($outputFile); - - $cachedImage = new CachedImage($this, $outputFile); - PartKeepr::getEM()->persist($cachedImage); - - return $outputFile; - } - - /** - * Scales the image to fit within the given size. - * - * @param int $w The width - * @param int $h The height - * @param boolean $padding If true, pad the output image to the given size (transparent background). - * @return string The path to the scaled file - */ - public function fitWithin ($w, $h, $padding = false) { - $this->ensureCachedirExists(); - - if ($padding) { - $pd = "p"; - } else { - $pd = ""; - } - - $outputFile = Configuration::getOption("partkeepr.images.cache").md5($this->getFilename().$w."x".$h."fw".$pd).".png"; - - if (file_exists($outputFile)) { - return $outputFile; - } - $image = new \Imagick(); - $image->readImage($this->getFilename()); - - $sourceAspectRatio = $image->getImageWidth() / $image->getImageHeight(); - $targetAspectRatio = $w / $h; - - $filter = \Imagick::FILTER_UNDEFINED; - $blur = 1; - - $targetHeight = $h; - $targetWidth = $w; - - if ($sourceAspectRatio < $targetAspectRatio) { - $targetWidth = $h * $sourceAspectRatio; - $image->resizeImage($h * $sourceAspectRatio, $h, $filter, $blur); - } else { - $targetHeight = $w / $sourceAspectRatio; - $image->resizeImage($w, $w / $sourceAspectRatio, $filter, $blur); - } - - if ($padding) { - $posX = intval(($w - $targetWidth) / 2); - $posY = intval(($h - $targetHeight) / 2); - - $image->extentImage($w, $h,-$posX, -$posY); - } - - $image->writeImage($outputFile); - - $cachedImage = new CachedImage($this, $outputFile); - PartKeepr::getEM()->persist($cachedImage); - - return $outputFile; - } - - /** - * Convinience method for fitWithin. Automatically pads the image. - * - * @param int $w The width - * @param int $h The height - * @return string The path to the scaled file - */ - public function fitWithinPadding ($w, $h) { - return $this->fitWithin($w, $h, true); - } - - /** - * Ensures that the image cache dir exists. - */ - public function ensureCachedirExists () { - if (!is_dir(Configuration::getOption("partkeepr.images.cache"))) { - mkdir(Configuration::getOption("partkeepr.images.cache"), 0777, true); - } - } - - /** - * Replaces the file with a given temporary file. - * @param string $id The temporary id (prefixed with TMP:) - */ - public function replaceFromTemporaryFile ($id) { - if (substr($id, 0, 4) === "TMP:") { - $tmpFileId = str_replace("TMP:", "", $id); - $tmpFile = TempImage::loadById($tmpFileId); - - $this->replace($tmpFile->getFilename()); - $this->setOriginalFilename($tmpFile->getOriginalFilename()); - - } - } - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Logger/Logger.php b/src/backend/de/RaumZeitLabor/PartKeepr/Logger/Logger.php @@ -1,121 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Logger; - -/** - * This class implements a simple logging mechanism. - * - * Might be replaced with some more advanced logging framework, but it serves its purpose for now. - */ -use de\RaumZeitLabor\PartKeepr\Util\Configuration; - -class Logger { - /** - * Loglevel "debug" - * - * You want to use this loglevel for debugging messages. - * @var string - */ - const LOGLEVEL_DEBUG = "debug"; - - /** - * Loglevel "info" - * - * You want to use this loglevel for informational messages where the program flow can continue normally and no - * impacts occur. - * - * @var string - */ - const LOGLEVEL_INFO = "info"; - - /** - * Loglevel "warning" - * - * You want to use this loglevel for messages where program flow can continue normally, but a minor - * impact can occur. - * - * @var string - */ - const LOGLEVEL_WARNING = "warning"; - - /** - * Loglevel "error" - * - * You want to use this loglevel for messages where program flow could be interrupted and major impacts occur. - * - * @var string - */ - const LOGLEVEL_ERROR = "error"; - - /** - * Loglevel "critical" - * - * You want to use this loglevel for messages where program flow could be interrupted and major impacts occur. - * - * @var string - */ - const LOGLEVEL_CRITICAL = "critical"; - - /** - * Logs a message. - * - * @param string $message The message to log - * @param string $severity One of the Logger::LOGLEVEL_* constants - */ - public static function log ($message, $severity = Logger::LOGLEVEL_INFO) { - if (Configuration::getOption("partkeepr.logger.enable", false) === false) { - // No logging wanted - return; - } - - $logFormat = "[%-19s] [%-8s] %s"; - - $outputFile = Configuration::getOption("partkeepr.logger.outputfile", sys_get_temp_dir() . "/partkeepr.log"); - $fp = fopen($outputFile, "a"); - - $date = date("Y-m-d H:i:s"); - - fputs($fp, sprintf($logFormat, $date, $severity, $message)."\n"); - - fclose($fp); - } - - /** - * Logs a message with the Logger::LOGLEVEL_DEBUG severity. - * @param string $message - */ - public static function logDebug ($message) { - self::log($message, Logger::LOGLEVEL_DEBUG); - } - - /** - * Logs a message with the Logger::LOGLEVEL_INFO severity. - * @param string $message - */ - public static function logInfo ($message) { - self::log($message, Logger::LOGLEVEL_INFO); - } - - /** - * Logs a message with the Logger::LOGLEVEL_WARNING severity. - * @param string $message - */ - public static function logWarning ($message) { - self::log($message, Logger::LOGLEVEL_WARNING); - } - - /** - * Logs a message with the Logger::LOGLEVEL_ERROR severity. - * @param string $message - */ - public static function logError ($message) { - self::log($message, Logger::LOGLEVEL_ERROR); - } - - /** - * Logs a message with the Logger::LOGLEVEL_CRITICAL severity. - * @param string $message - */ - public static function logCritical ($message) { - self::log($message, Logger::LOGLEVEL_CRITICAL); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manager/AbstractManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manager/AbstractManager.php @@ -1,230 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manager; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\PartKeepr, - Doctrine\ORM\QueryBuilder, - Doctrine\ORM\Query, - de\RaumZeitLabor\PartKeepr\Manager\Exceptions\EntityInUseException; - -/** - * The AbstractManager is a very basic helper which - * implements the mostly used operations on entities: - * - * - Create - * - Delete - * - List - * - */ -abstract class AbstractManager extends Singleton { - /** - * Returns the FQCN for the target entity to operate on. - * - * Needs to be implemented by the parent class. - * - * @return string The FQCN, e.g. de\RaumZeitLabor\PartKeepr\Part - */ - abstract public function getEntityName (); - - /** - * Returns all fields which need to appear in the getList ResultSet. - * - * This should include all fields required by the frontend. - * - * @return array An array of all fields which should be returned - */ - abstract public function getQueryFields (); - - /** - * Returns the default sort field - * - * @return string The default sort field - */ - abstract public function getDefaultSortField (); - - /** - * Loads an entity by id - * - * @param int $id The entity id - */ - public function getEntity ($id) { - return call_user_func($this->getEntityName()."::loadById", $id); - } - - /** - * Removes a specific entity from the system - * @param int $id - * @throws EntityInUseException Is thrown when the entity is in use - */ - public function deleteEntity ($id) { - $entity = $this->getEntity($id); - - try { - PartKeepr::getEM()->remove($entity); - PartKeepr::getEM()->flush(); - } catch (\PDOException $e) { - if ($e->getCode() == "23000") { - throw new EntityInUseException($entity); - } - } - } - - /** - * Creates a new entity from an array of parameters - * @param array $parameters An array which gets passed to the deserialize method - */ - public function createEntity ($parameters) { - $class = $this->getEntityName(); - $entity = new $class; - $entity->deserialize($parameters); - - PartKeepr::getEM()->persist($entity); - PartKeepr::getEM()->flush(); - - return $entity; - } - - /** - * Returns a list of entities. - * - * @param ManagerFilter $filter The filter settings for this query - */ - public function getList (ManagerFilter $filter) { - $qb = PartKeepr::getEM()->createQueryBuilder(); - - $qb->select("COUNT(q.id)")->from($this->getEntityName(),"q"); - - $this->applyFiltering($qb, $filter); - $this->applyCustomQuery($qb, $filter); - - $totalQuery = $qb->getQuery(); - - $this->applyResultFields($qb, $filter); - $this->applyPagination($qb, $filter); - $this->applySorting($qb, $filter); - - $query = $qb->getQuery(); - - return array("data" => $this->getResult($query), "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Processes the result after it was retrieved. In the default configuration, it returns an array result, or - * if no query fields are specified, it tries to serialize all objects. - */ - protected function getResult (Query $query) { - if (count($this->getQueryFields()) == 0) { - $aSerializedResult = array(); - foreach ($query->getResult() as $result) { - $aSerializedResult[] = $result->serialize(); - } - - return $aSerializedResult; - } else { - return $query->getArrayResult(); - } - } - - /** - * Applies the result fields to the query. - * - * The result fields can be prefixed with the table alias or not; if not prefixed, it is assumed that we'll be - * using the specified entity FQCN. - * - * Note that the base name will be always "q", so avoid "q" as alias for joined tables. - * - * @param QueryBuilder $qb The query builder - * @param ManagerFilter $filter The query filter - */ - protected function applyResultFields (QueryBuilder $qb, ManagerFilter $filter) { - if (count($this->getQueryFields()) == 0) { - $qb->select("q"); - } else { - // Prepend a prefix to each field - $aQueryFields = array(); - foreach ($this->getQueryFields() as $field) { - - if (strpos($field, ".") === false) { - // The field is not prefixed, prepend the q. prefix - $aQueryFields[] = "q.".$field; - } else { - // Use as-is - $aQueryFields[] = $field; - } - } - - $qb->select($aQueryFields); - } - } - - /** - * Applies filtering to the query and calls back the custom filtering function, if required. - * - * @param QueryBuilder $qb The query builder - * @param ManagerFilter $filter The query filter - */ - protected function applyFiltering (QueryBuilder $qb, ManagerFilter $filter) { - if ($filter->getFilter() !== null && $filter->getFilterField() !== null) { - $aOrWhereFields = array(); - - if (is_array($filter->getFilterField())) { - foreach ($filter->getFilterField() as $field) { - $aOrWhereFields[] = "LOWER(q.".$field.") LIKE :filter"; - } - } else { - $aOrWhereFields[] = "LOWER(q.".$filter->getFilterField().") LIKE :filter"; - } - - foreach ($aOrWhereFields as $or) { - $qb->orWhere($or); - } - - $qb->setParameter("filter", "%".strtolower($filter->getFilter())."%"); - } - - if ($filter->getFilterCallback() !== null) { - call_user_func($filter->getFilterCallback(), $qb); - } - } - - - /** - * Applies a custom query to the QueryBuilder - * - * @param QueryBuilder $qb The query builder - * @param ManagerFilter $filter The query filter - */ - protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { - - } - - /** - * Applies pagination to the query - * - * @param QueryBuilder $qb The query builder - * @param ManagerFilter $filter The query filter - */ - protected function applyPagination (QueryBuilder $qb, ManagerFilter $filter) { - if ($filter->getStart() !== null && $filter->getLimit() !== null) { - $qb->setFirstResult($filter->getStart()); - } - - if ($filter->getLimit() !== null) { - $qb->setMaxResults($filter->getLimit()); - } - } - - /** - * Applies record sorting - * - * @param QueryBuilder $qb The query builder - * @param ManagerFilter $filter The query filter - */ - protected function applySorting (QueryBuilder $qb, ManagerFilter $filter) { - foreach ($filter->getSorters() as $sorter) { - if ($sorter->getSortField() !== null && $sorter->getSortField() != "q.") { - $qb->addOrderBy($sorter->getSortField(), $sorter->getSortDirection()); - } - } - } -} - \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manager/Exceptions/EntityInUseException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manager/Exceptions/EntityInUseException.php @@ -1,31 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manager\Exceptions; - -/** - * This exception is thrown when an entity should be deleted, but is in use by other entities. - * @author felicitus - */ -class EntityInUseException extends \Exception { - - /** - * The entity - * @var BaseEntity - */ - private $entity; - - /** - * Constructs the exception - * @param BaseEntity $entity - */ - public function __construct (\de\RaumZeitLabor\PartKeepr\Util\BaseEntity $entity) { - parent::__construct(sprintf("Entity %s is referenced by other entities, can't delete", get_class($entity))); - $this->entity = $entity; - } - - /** - * Returns the entity which caused the error - */ - public function getEntity () { - return $this->entity; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manager/ManagerFilter.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manager/ManagerFilter.php @@ -1,196 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manager; - -use de\RaumZeitLabor\PartKeepr\Service\Service; - -class ManagerFilter { - /** - * Specifies the record index at which to start - * @var integer - */ - protected $start = 0; - - /** - * Specifies the number of records to retrieve - * @var integer - */ - protected $limit = null; - - /** - * Specifies a string to filter for. Can either be a string - * or null if no filter is wanted - * @var string - */ - protected $filter = null; - - /** - * Specifies the field (or a list of fields) to apply the filter on - * @var mixed null if disabled, a string for a single field or an array of fields - */ - protected $filterField = null; - - /** - * Specifies the fields to sort by - * @var array - */ - protected $sorters = array(); - - /** - * A callback which is called when creating the filter - * @var function The callback - */ - protected $callback = null; - - /** - * Sets the start position - * @param int $start - */ - public function setStart ($start) { - $this->start = intval($start); - } - - /** - * Returns the start position - * @return int - */ - public function getStart () { - if ($this->start === null) { - return 0; - } else { - return $this->start; - } - } - - /** - * Sets the number of records to retrieve - * @param mixed $limit Either a positive integer, or null/-1 for no limit - */ - public function setLimit ($limit) { - if ($limit === null || $limit == -1) { - $this->limit = null; - } else { - $this->limit = intval($limit); - } - } - - /** - * Returns the number of records to retrieve - * @return int - */ - public function getLimit () { - return $this->limit; - } - - /** - * Sets the sorters for this filter. - * - * @param array $sorters An array of Sorter instances - */ - public function setSorters (array $sorters) { - // Make sure that each sorter is an instance of the Sorter class. - foreach ($sorters as $sorter) { - if (!($sorter instanceof Sorter)) { - throw new InvalidArgumentException("The passed sorters needs to be an array of Sorter instances"); - } - } - - $this->sorters = $sorters; - } - - /** - * Returns the sorters for this filter. - * @return array An array of Sorter instances - */ - public function getSorters () { - return $this->sorters; - } - - /** - * Sets the filter. Specify null if no filter is wanted. - * @param mixed $filter A string to filter for, or null to disable - */ - public function setFilter ($filter) { - $this->filter = $filter; - } - - /** - * Returns the filter. - * @return mixed Either a string to filter for, or null if disabled - */ - public function getFilter () { - return $this->filter; - } - - /** - * Sets the field(s) to filter for. - * - * If multiple fields are specified, they will be combined using an "OR" clause. - * - * @param mixed $field Either null to disable, a single string to specify a field, or an array of string fields - */ - public function setFilterField ($field) { - $this->filterField = $field; - } - - /** - * Returns the field(s) to filter for - * @return mixed See setFilterField - */ - public function getFilterField () { - return $this->filterField; - } - - /** - * Sets the filter callback - * @param function $callback A function which is called when creating a filter. The callback function receives the - * query builder as first argument. - */ - public function setFilterCallback ($callback) { - $this->callback = $callback; - } - - /** - * Returns the filter callback - * @return function The callback function - */ - public function getFilterCallback () { - return $this->callback; - } - - /** - * Constructs a new filter set. - * - * If a service is passed, the constructor automatically extracts the parameters from the service - * - * @todo Document which parameters we have - * - * @param Service $service A service to extract the information from, or null - */ - public function __construct (Service $service = null) { - if (is_object($service)) { - if ($service->hasParameter("start")) { - $this->setStart($service->getParameter("start", null)); - } - - if ($service->hasParameter("limit")) { - $this->setLimit($service->getParameter("limit", null)); - } - - if ($service->hasParameter("sort")) { - $tmp = json_decode($service->getParameter("sort"), true); - - $aSorters = array(); - - foreach ($tmp as $key => $sortParam) { - $aSorters[] = new Sorter("q.".$sortParam["property"], $sortParam["direction"]); - } - - $this->setSorters($aSorters); - } - - if ($service->hasParameter("query")) { - $this->setFilter($service->getParameter("query")); - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manager/Sorter.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manager/Sorter.php @@ -1,79 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manager; - -/** - * Represents a sorter, which is used with the ManagerFilter class. - * - * This allows the developer to specify multiple sorters. One sorter contains a sort field and a sort direction. - */ -class Sorter { - /** - * The field to sort by - * @var string - */ - private $sortField = null; - - /** - * The direction to sort by - * @var string - */ - private $sortDirection = null; - - /** - * Constructs a new sorter. - * - * @param string $field The field to sort by - * @param string $direction The direction, either "asc" or "desc" - */ - public function __construct ($field = null, $direction = null) { - if ($field !== null) { - $this->setSortField($field); - } - - if ($direction !== null) { - $this->setSortDirection($direction); - } - } - - /** - * Sets the sort field for this sorter - * @param string $field The field to sort by - */ - public function setSortField ($field) { - $this->sortField = $field; - } - - /** - * Sets the sort direction for this sorter - * @param string $direction Either "asc" or "desc" - */ - public function setSortDirection ($direction) { - switch (strtolower($direction)) { - case "desc": - case "d": - $this->sortDirection = "desc"; - break; - case "asc": - case "a": - default: - $this->sortDirection = "asc"; - break; - } - } - - /** - * Returns the sort field for this sorter - * @return string The field name - */ - public function getSortField () { - return $this->sortField; - } - - /** - * Returns the sort order for this sorter - * @return string Either "asc" or "desc" - */ - public function getSortDirection () { - return $this->sortDirection; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/Manufacturer.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/Manufacturer.php @@ -1,250 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manufacturer; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Represents a manufacturer - * @Entity **/ -class Manufacturer extends BaseEntity implements Serializable, Deserializable { - /** - * The name of the manufacturer - * @Column(type="string",unique=true) - * @var string - */ - private $name; - - /** - * The address of the manufacturer - * @Column(type="text",nullable=true) - * @var string - */ - private $address; - - /** - * The URL - * @Column(type="string",nullable=true) - * @var string - */ - private $url; - - /** - * The email - * @Column(type="string",nullable=true) - * @var string - */ - private $email; - - /** - * The comment - * @Column(type="text",nullable=true) - * @var string - */ - private $comment; - - /** - * The phone number - * @Column(type="string",nullable=true) - * @var string - */ - private $phone; - - /** - * The fax number - * @Column(type="string",nullable=true) - * @var string - */ - private $fax; - - /** - * All ic logos of this manufacturer - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo",mappedBy="manufacturer",cascade={"persist", "remove"}) - */ - private $icLogos; - - /** - * Creates a new manufacturer instance - */ - public function __construct () { - $this->icLogos = new \Doctrine\Common\Collections\ArrayCollection(); - } - - /** - * Sets the name - * @param string $name The name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name - * @return string The name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the phone number - * @param string $phone The phone number - */ - public function setPhone ($phone) { - $this->phone = $phone; - } - - /** - * Returns the phone number - * @return string The phone number - */ - public function getPhone () { - return $this->phone; - } - - /** - * Sets the fax number - * @param string $fax The fax number - */ - public function setFax ($fax) { - $this->fax = $fax; - } - - /** - * Returns the fax number - * @return string The fax number - */ - public function getFax () { - return $this->fax; - } - - /** - * Sets the address - * @param string $address The address - */ - public function setAddress ($address) { - $this->address = $address; - } - - /** - * Returns the address - * @return string The address - */ - public function getAddress () { - return $this->address; - } - - /** - * Sets the comment - * @param string $comment The comment - */ - public function setComment ($comment) { - $this->comment = $comment; - } - - /** - * Returns the comment - * @return string The comment - */ - public function getComment () { - return $this->comment; - } - - /** - * Sets the email - * @param string $email The email - */ - public function setEmail ($email) { - $this->email = $email; - } - - /** - * Returns the email - * @return string The email - */ - public function getEmail () { - return $this->email; - } - - /** - * Sets the URL - * @param string $url The URL - */ - public function setURL ($url) { - $this->url = $url; - } - - /** - * Returns the URL - * @return string The url - */ - public function getURL () { - return $this->url; - } - - /** - * Returns the ic logos - * @return ArrayCollection The array with all ic logos - */ - public function getICLogos () { - return $this->icLogos; - } - - /** - * Returns this manufacturer in serialized form - * @return array The serialized manufacturer - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "url" => $this->getURL(), - "address" => $this->getAddress(), - "email" => $this->getEmail(), - "comment" => $this->getComment(), - "phone" => $this->getPhone(), - "fax" => $this->getFax(), - "iclogos" => $this->serializeChildren($this->getICLogos()) - ); - } - - /** - * Deserializes the manufacturer - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "url": - $this->setURL($value); - break; - case "comment": - $this->setComment($value); - break; - case "email": - $this->setEmail($value); - break; - case "fax": - $this->setFax($value); - break; - case "phone": - $this->setPhone($value); - break; - case "address": - $this->setAddress($value); - break; - case "iclogos": - $this->deserializeChildren($value, $this->getICLogos(), "de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo"); - foreach ($this->getICLogos() as $iclogo) { - $iclogo->setManufacturer($this); - } - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerICLogo.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerICLogo.php @@ -1,63 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manufacturer; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Image\Image; - -/** - * Holds a manufacturer IC logo - * @Entity - **/ -class ManufacturerICLogo extends Image implements Serializable, Deserializable { - /** - * The manufacturer object - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer") - * @var Manufacturer - */ - private $manufacturer = null; - - /** - * Creates a new IC logo instance - */ - public function __construct () { - parent::__construct(Image::IMAGE_ICLOGO); - } - - /** - * Sets the manufacturer - * @param Manufacturer $manufacturer The manufacturer to set - */ - public function setManufacturer (Manufacturer $manufacturer) { - $this->manufacturer = $manufacturer; - } - - /** - * Returns the manufacturer - * @return Manufacturer the manufacturer - */ - public function getManufacturer () { - return $this->manufacturer; - } - - /** - * - * Serializes this ic logo - * @return array The serialized ic logo - */ - public function serialize () { - return array("id" => $this->getId(), "manufacturer_id" => $this->getManufacturer()->getId()); - } - - /** - * Deserializes the iclogo - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - if (array_key_exists("id", $parameters)) { - if (substr($parameters["id"], 0, 4) === "TMP:") { - $this->replaceFromTemporaryFile($parameters["id"]); - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerManager.php @@ -1,104 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manufacturer; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, - de\RaumZeitLabor\PartKeepr\Manufacturer\Exceptions\ManufacturerNotFoundException; - -class ManufacturerManager extends Singleton { - /** - * Returns a list of manufacturers. - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter A string to filter the manufacturer's name by, default empty - */ - public function getManufacturers ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st.id, st.name, st.url, st.email, st.comment, st.address")->from("de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer","st"); - - if ($filter != "") { - $qb = $qb->where("LOWER(st.name) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Adds a new manufacturer by name - * - * @param string $name The manufacturer name - */ - public function addManufacturer ($name) { - $manufacturer = new Manufacturer(); - $manufacturer->setName($name); - - PartKeepr::getEM()->persist($manufacturer); - PartKeepr::getEM()->flush(); - - return $manufacturer; - } - - /** - * Loads a manufacturer by id - * - * @param int $id The manufacturer id - */ - public function getManufacturer ($id) { - return Manufacturer::loadById($id); - } - - /** - * Deletes the manufacturer by id - * @param int $id The manufacturer's id - */ - public function deleteManufacturer ($id) { - $manufacturer = Manufacturer::loadById($id); - - PartKeepr::getEM()->remove($manufacturer); - PartKeepr::getEM()->flush(); - } - - /** - * Retrieves a manufacturer by its name. - * - * @param string $name The name of the manufacturer to retrieve - * @throws Doctrine\ORM\NoResultException If the manufacturer was not found - */ - public function getManufacturerByName ($name) { - $dql = "SELECT m FROM de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer m WHERE m.name = :name"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $name); - - return $query->getSingleResult(); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Manufacturer/ManufacturerService.php @@ -1,82 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Manufacturer; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService; - -use de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class ManufacturerService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return array("data" => ManufacturerManager::getInstance()->getManufacturer($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "name", - "direction" => "ASC"); - } - return ManufacturerManager::getInstance()->getManufacturers( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $this->requireParameter("name"); - - $manufacturer = new Manufacturer; - $manufacturer->deserialize($this->getParameters()); - - PartKeepr::getEM()->persist($manufacturer); - PartKeepr::getEM()->flush(); - - return array("data" => $manufacturer->serialize()); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - $manufacturer = ManufacturerManager::getInstance()->getManufacturer($this->getParameter("id")); - $manufacturer->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $manufacturer->serialize()); - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - ManufacturerManager::getInstance()->deleteManufacturer($this->getParameter("id")); - - return array("data" => null); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/ManufacturerICLogo/ManufacturerICLogoManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/ManufacturerICLogo/ManufacturerICLogoManager.php @@ -1,65 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\ManufacturerICLogo; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manufacturer\Exceptions\ManufacturerNotFoundException; - -class ManufacturerICLogoManager extends Singleton { - /** - * Returns a list of manufacturer ic logos. - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter The manufacturer id - */ - public function getManufacturerICLogos ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st.id, maf.id AS manufacturer_id")->from("de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo","st") - ->leftJoin('st.manufacturer', "maf"); - - 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("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("st.manufacturer = :manufacturer"); - $totalQueryBuilder->setParameter("manufacturer", $manufacturer); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Returns a manufacturer ic logo by id - * @param int $id The manufacturer ic logo id - */ - public function getManufacturerICLogo ($id) { - return ManufacturerICLogo::loadById($id); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/ManufacturerICLogo/ManufacturerICLogoService.php b/src/backend/de/RaumZeitLabor/PartKeepr/ManufacturerICLogo/ManufacturerICLogoService.php @@ -1,101 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\ManufacturerICLogo; - -use de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo, - de\RaumZeitLabor\PartKeepr\TempImage\TempImage, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class ManufacturerICLogoService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return ManufacturerICLogoManager::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"]; - } - } - } - } - } - 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); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - 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()); - $image->setOriginalFilename($tmpImage->getOriginalFilename()); - PartKeepr::getEM()->persist($image); - PartKeepr::getEM()->flush(); - - return $image->serialize(); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - 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/de/RaumZeitLabor/PartKeepr/Part/Exceptions/CategoryNotAssignedException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/Exceptions/CategoryNotAssignedException.php @@ -1,20 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part\Exceptions; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\Part\Part; - -/** - * This exception is thrown when a part hasn't got a category assigned - */ -class CategoryNotAssignedException extends SerializableException { - - /** - * Constructs the exception - * @param BaseEntity $entity - */ - public function __construct (Part $part) { - parent::__construct(PartKeepr::i18n("Part %s has no category assigned", $part)); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/Exceptions/StorageLocationNotAssignedException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/Exceptions/StorageLocationNotAssignedException.php @@ -1,19 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part\Exceptions; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\SerializableException; - -/** - * This exception is thrown when a part hasn't got a storage location assigned - */ -class StorageLocationNotAssignedException extends SerializableException { - - /** - * Constructs the exception - * @param BaseEntity $entity - */ - public function __construct () { - parent::__construct(PartKeepr::i18n("No storage location assigned")); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/Part.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/Part.php @@ -1,640 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\Exceptions\CategoryNotAssignedException, - de\RaumZeitLabor\PartKeepr\Util\Exceptions\OutOfRangeException, - de\RaumZeitLabor\PartKeepr\Part\Exceptions\StorageLocationNotAssignedException; - - -/** - * Represents a part in the database. The heart of our project. Handle with care! - * - * @Entity @HasLifecycleCallbacks - */ -class Part extends BaseEntity implements Serializable, Deserializable { - /** - * The category of the part - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory") - * @var Category - */ - private $category; - - /** - * The part's name - * @Column - * @var string - */ - private $name; - - /** - * The part's short description - * @Column(type="string",nullable=true) - * @var string - */ - private $description; - - /** - * The footprint of this part - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Footprint\Footprint") - * @var Footprint - */ - private $footprint; - - /** - * The unit in which the part's "amount" is calculated. This is necessary to count parts - * in "pieces", "meters" or "grams". - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\PartUnit") - * @var PartUnit - */ - private $partUnit; - - /** - * Defines the storage location of this part - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation") - * @var StorageLocation - */ - private $storageLocation; - - /** - * Holds the manufacturers which can manufacture this part - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Part\PartManufacturer",mappedBy="part",cascade={"persist", "remove"}) - * @var ArrayCollection - */ - private $manufacturers; - - /** - * Holds the distributors from where we can buy the part - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Part\PartDistributor",mappedBy="part",cascade={"persist", "remove"}) - * @var ArrayCollection - */ - private $distributors; - - /** - * Holds the part images - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Part\PartImage",mappedBy="part",cascade={"persist", "remove"}) - * @var PartImage - */ - private $images; - - /** - * Holds the part attachments - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Part\PartAttachment",mappedBy="part",cascade={"persist", "remove"}) - * @var PartAttachment - */ - private $attachments; - - /** - * The comment for this part - * @Column(type="text") - */ - private $comment = ""; - - /** - * The stock level. Note that this is a cached value, because it makes our summary queries easier. - * @todo It would be nice if we could get rid of that. - * @Column(type="integer") - * @var integer - */ - private $stockLevel = 0; - - /** - * The minimum stock level for this part. If we run out of this part (e.g. stockLevel < minStockLevel), - * we can see that in the system and re-order parts. - * - * @Column(type="integer") - * @var integer - */ - private $minStockLevel = 0; - - /** - * The average price for the part. Note that this is a cached value. - * - * @todo It would be nice if we could get rid of that - * @Column(type="decimal",precision=13,scale=4,nullable=true) - * @var float - */ - private $averagePrice = null; - - /** - * The stock level history - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Stock\StockEntry",mappedBy="part",cascade={"persist", "remove"}) - * @var ArrayCollection - */ - private $stockLevels; - - /** - * The parameters for this part - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter",mappedBy="part",cascade={"persist", "remove"}) - * @var ArrayCollection - */ - private $parameters; - - /** - * The part status for this part - * @Column(type="string",nullable=true) - * @var string - */ - private $status; - - /** - * Defines if the part needs review - * @Column(type="boolean") - * @var boolean - */ - private $needsReview; - - /** - * The create date+time for this part - * @Column(type="datetime",nullable=true) - * @var \DateTime - */ - private $createDate; - - /** - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Project\Project", mappedBy="part") - **/ - private $projects; - - /** - * The internal part number - * @Column(type="string",nullable=true) - * @var string - */ - private $internalPartNumber; - - public function __construct () { - $this->distributors = new \Doctrine\Common\Collections\ArrayCollection(); - $this->manufacturers = new \Doctrine\Common\Collections\ArrayCollection(); - $this->parameters = new \Doctrine\Common\Collections\ArrayCollection(); - $this->images = new \Doctrine\Common\Collections\ArrayCollection(); - $this->attachments = new \Doctrine\Common\Collections\ArrayCollection(); - $this->setCreateDate(new \DateTime()); - $this->setReviewFlag(false); - } - - /** - * Sets the name for this part - * @param string $name The part's name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of this part - * @return string The part name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the internal part number for this part - * @param string $partnumber - */ - public function setInternalPartNumber ($partNumber) { - $this->internalPartNumber = $partNumber; - } - - /** - * Returns the internal part number for this part - * @return string the internal part number - */ - public function getInternalPartNumber () { - return $this->internalPartNumber; - } - - /** - * Sets the description for this part - * @param string $description The part's short description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the short description of this part - * @return string The part description - */ - public function getDescription () { - return $this->description; - } - - /** - * Sets the part unit - * - * @param PartUnit $partUnit The part unit object to set - * @return nothing - */ - public function setPartUnit (PartUnit $partUnit) { - $this->partUnit = $partUnit; - } - - /** - * Returns the part unit - * - * @param none - * @return PartUnit The part unit object - */ - public function getPartUnit () { - return $this->partUnit; - } - - /** - * Sets the average price for this unit - * @todo Is this actually used? - * @param float $price The price to set - */ - public function setAveragePrice ($price) { - $this->averagePrice = $price; - } - - /** - * Updates the internal stock level from the stock history - */ - public function updateStockLevel () { - $this->stockLevel = $this->getStockLevel(); - } - - /** - * Sets the review flag - * @param boolean $bReview True if the part needs review, false otherwise - */ - public function setReviewFlag ($bReview) { - $this->needsReview = $bReview; - } - - /** - * Returns the review flag - * @return boolean True if the part needs review, false otherwise - */ - public function getReviewFlag () { - return $this->needsReview; - } - - /** - * Set the minimum stock level for this part - * - * Only positive values are allowed. - * - * @param int $minStockLevel A minimum stock level, only values >= 0 are allowed. - * @throws \de\RaumZeitLabor\PartKeepr\Util\Exceptions\OutOfRangeException If the passed stock level is not in range (>=0) - */ - public function setMinStockLevel ($minStockLevel) { - $minStockLevel = intval($minStockLevel); - - if ($minStockLevel < 0) { - $exception = new OutOfRangeException(PartKeepr::i18n("Minimum Stock Level is out of range")); - $exception->setDetail(PartKeepr::i18n("The minimum stock level must be 0 or higher")); - throw $exception; - } - $this->minStockLevel = $minStockLevel; - } - - /** - * Sets the category for this part - * @param \de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory $category The category - */ - public function setCategory (PartCategory $category) { - $this->category = $category; - } - - /** - * Returns the assigned category - * @return \de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory - */ - public function getCategory () { - return $this->category; - } - - /** - * Returns all projects this part is used - * @return ArrayCollection the projects - */ - public function getProjects () { - return $this->projects; - } - - /** - * Sets the storage location for this part - * @param \de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation $storageLocation The storage location - */ - public function setStorageLocation (StorageLocation $storageLocation) { - $this->storageLocation = $storageLocation; - } - - /** - * Returns the storage location for this part - * @return \de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation $storageLocation The storage location - */ - public function getStorageLocation () { - return $this->storageLocation; - } - - /** - * Sets the footprint for this part - * @param \de\RaumZeitLabor\PartKeepr\Footprint\Footprint $footprint The footprint to set - */ - public function setFootprint (Footprint $footprint = null) { - $this->footprint = $footprint; - } - - /** - * Sets the comment for this part - * @param string $comment The comment for this part - */ - public function setComment ($comment) { - $this->comment = $comment; - } - - /** - * Returns the comment for this part - * @return string The comment - */ - public function getComment () { - return $this->comment; - } - - /** - * Returns the distributors array - * @return ArrayCollection the distributors - */ - public function getDistributors () { - return $this->distributors; - } - - /** - * Returns the part images array - * @return ArrayCollection the part images - */ - public function getImages () { - return $this->images; - } - - /** - * Returns the part attachments array - * @return ArrayCollection the part attachments - */ - public function getAttachments () { - return $this->attachments; - } - - /** - * Returns the manufacturers array - * @return ArrayCollection the manufactuers - */ - public function getManufacturers () { - return $this->manufacturers; - } - - /** - * Returns the parameters assigned to this part - * @return array An array of PartParameter objects - */ - public function getParameters () { - return $this->parameters; - } - - /** - * Returns the stock level of this part. This is a realtime function which - * actually creates a query over the StockEntry table. - * @return int The stock level - */ - public function getStockLevel () { - $query = PartKeepr::getEM()->createQuery("SELECT SUM(s.stockLevel) FROM de\RaumZeitLabor\PartKeepr\Stock\StockEntry s WHERE s.part = :part"); - $query->setParameter("part", $this); - - return $query->getSingleScalarResult(); - } - - /** - * Sets the create date for this part - * @param \DateTime $dateTime The create date+time - */ - private function setCreateDate (\DateTime $dateTime) { - $this->createDate = $dateTime; - } - - /** - * Returns the create date - * @return \DateTime The create date+time - */ - public function getCreateDate () { - return $this->createDate; - } - - /** - * Sets the status for this part. A status is any string describing the status, - * e.g. "new", "used", "broken" etc. - * @param string $status The status - */ - public function setStatus ($status) { - $this->status = $status; - } - - /** - * Returns the status for this part. - * @return string The status - */ - public function getStatus () { - return $this->status; - } - - public function updateCacheData () { - $this->updateStockLevel(); - $this->updatePrice(); - } - - /** - * Updates the average price for a part - */ - public function updatePrice () { - $query = PartKeepr::getEM()->createQuery("SELECT SUM(se.price*se.stockLevel) / SUM(se.stockLevel) FROM de\RaumZeitLabor\PartKeepr\Stock\StockEntry se WHERE se.part = :part AND se.stockLevel > 0"); - $query->setParameter("part", $this); - $val = $query->getSingleScalarResult(); - - $query = PartKeepr::getEM()->createQuery('UPDATE de\RaumZeitLabor\PartKeepr\Part\Part p SET p.averagePrice = :val WHERE p = :part'); - $query->setParameter("val", $val); - $query->setParameter("part", $this); - $query->execute(); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription(), - "comment" => $this->getComment(), - "stockLevel" => $this->getStockLevel(), - "footprint" => is_object($this->footprint) ? $this->footprint->getId() : null, - "minStockLevel" => $this->minStockLevel, - "status" => $this->getStatus(), - "storageLocation" => is_object($this->storageLocation) ? $this->storageLocation->getId() : null, - "category" => is_object($this->category) ? $this->category->getId() : null, - "partUnit" => is_object($this->partUnit) ? $this->getPartUnit()->getId() : null, - "manufacturers" => $this->serializeChildren($this->getManufacturers()), - "distributors" => $this->serializeChildren($this->getDistributors()), - "images" => $this->serializeChildren($this->getImages()), - "attachments" => $this->serializeChildren($this->getAttachments()), - "parameters" => $this->serializeChildren($this->getParameters()), - "createDate" => $this->getCreateDate()->format("Y-m-d H:i:s"), - "needsReview" => $this->getReviewFlag(), - "internalPartNumber" => $this->getInternalPartNumber(), - // Additional things we serialize to make displaying stuff in the frontend easier - "categoryName" => is_object($this->category) ? $this->category->getName() : null, - "footprintName" => is_object($this->footprint) ? $this->footprint->getName() : null, - "storageLocationName" => is_object($this->storageLocation) ? $this->storageLocation->getName() : null - ); - } - - /** - * Deserializes the part - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "description": - $this->setDescription($value); - break; - case "comment": - $this->setComment($value); - break; - case "internalPartNumber": - $this->setInternalPartNumber($value); - break; - case "footprint": - if ($value === 0) { - $this->setFootprint(null); - } else { - try { - $footprint = Footprint::loadById($value); - $this->setFootprint($footprint); - } catch (\Exception $e) { - // No footprint was found. Ignore it. - } - } - break; - case "minStockLevel": - $this->setMinStockLevel($value); - break; - case "partUnit": - $partUnit = PartUnit::loadById($value); - $this->setPartUnit($partUnit); - break; - case "category": - $category = PartCategory::loadById($value); - $this->setCategory($category); - break; - case "status": - $this->setStatus($value); - break; - case "storageLocation": - $storageLocation = StorageLocation::loadById($value); - $this->setStorageLocation($storageLocation); - break; - case "manufacturers": - $this->deserializeChildren($value, $this->getManufacturers(), "de\RaumZeitLabor\PartKeepr\Part\PartManufacturer"); - foreach ($this->getManufacturers() as $manufacturer) { - $manufacturer->setPart($this); - } - break; - case "distributors": - $this->deserializeChildren($value, $this->getDistributors(), "de\RaumZeitLabor\PartKeepr\Part\PartDistributor"); - foreach ($this->getDistributors() as $distributor) { - $distributor->setPart($this); - } - break; - case "parameters": - $this->deserializeChildren($value, $this->getParameters(), "de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter"); - foreach ($this->getParameters() as $parameter) { - $parameter->setPart($this); - } - break; - case "needsReview": - $this->setReviewFlag($value); - break; - case "attachments": - $this->deserializeChildren($value, $this->getAttachments(), "de\RaumZeitLabor\PartKeepr\Part\PartAttachment"); - foreach ($this->getAttachments() as $attachment) { - $attachment->setPart($this); - } - break; - } - } - } - - /** - * Checks if the part category is set. - * - * @throws CategoryNotAssignedException - */ - private function checkCategoryConsistency () { - if ($this->getCategory() === null) { - throw new CategoryNotAssignedException($this); - } - } - - /** - * Checks if the part storage location is set. - * - * @throws StorageLocationNotAssignedException - */ - private function checkStorageLocationConsistency () { - if ($this->getStorageLocation() === null) { - throw new StorageLocationNotAssignedException(); - } - } - - /** - * Checks if the requirements for database persisting are given. - * - * @throws CategoryNotAssignedException Thrown if no category is set - * @throws StorageLocationNotAssignedException Thrown if no storage location is set - * - * @PrePersist - */ - public function onPrePersist () { - $this->checkCategoryConsistency(); - $this->checkStorageLocationConsistency(); - } - - /** - * - * Checks if the requirements for database persisting are given. - * - * For a list of exceptions, see - * @see de\RaumZeitLabor\PartKeepr\Part.Part::onPrePersist() - * - * @PreUpdate */ - public function onPreUpdate () { - $this->checkCategoryConsistency(); - $this->checkStorageLocationConsistency(); - } - - /** - * Returns a string representation of the part - * - * @param none - * @return string The name and the ID of the part - */ - public function __toString () { - return $this->getName() . " (".$this->getId().")"; - } - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartAttachment.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartAttachment.php @@ -1,128 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\UploadedFile\UploadedFile; - -/** - * Holds a part attachment - * @Entity - **/ -class PartAttachment extends UploadedFile implements Serializable, Deserializable { - /** - * The description of this attachment - * @Column(type="text") - * @var string - */ - private $description; - - /** - * Creates a new part attachment - */ - public function __construct () { - parent::__construct(); - $this->setType("PartAttachment"); - } - /** - * The part object - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - * @var Part - */ - private $part = null; - - /** - * Sets the part - * @param Part $part The part to set - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part - * @return Part the part - */ - public function getPart () { - return $this->part; - } - - /** - * Sets the description for this attachment - * @param string $description The attachment description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description for this attachment - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * - * Serializes this part attachment - * @return array The serialized part attachment - */ - public function serialize () { - return array( - "id" => $this->getId(), - "part_id" => $this->getPart()->getId(), - "originalFilename" => $this->getOriginalFilename(), - "mimetype" => $this->getMimetype(), - "extension" => $this->getExtension(), - "size" => $this->getSize(), - "description" => $this->getDescription(), - "image" => $this->isImage()); - } - - /** - * Deserializes the part attachment - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - if (array_key_exists("id", $parameters)) { - if (substr($parameters["id"], 0, 4) === "TMP:") { - $this->replaceFromTemporaryFile($parameters["id"]); - } - } - - foreach ($parameters as $key => $value) { - switch ($key) { - case "description": - $this->setDescription($value); - break; - } - } - } - - /** - * Returns if the attachment is an image or not. - * - * Ths method uses ImageMagick to find out if this is an image. Limitations apply; if ImageMagick doesn't support - * the image format, this method would return false, even if it is an image. - * - * @return True if the attachment is an image, false otherwise - */ - public function isImage () { - /** - * Special case: Check if it's a PDF. If yes, return immediately. - * This is because ImageMagick outputs warning messages for malformed PDF files, and halts the execution - * of the script for several seconds. DO NOT REMOVE! - */ - if ($this->getMimeType() == "application/pdf") { - return false; - } - - try { - $im = new \Imagick($this->getFilename()); - return true; - } catch (\ImagickException $e) { - return false; - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartDistributor.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartDistributor.php @@ -1,193 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Distributor\Distributor; - -/** - * This class represents the link between a part and a distributor. - * @Entity **/ -class PartDistributor extends BaseEntity implements Serializable, Deserializable { - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - */ - private $part; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Distributor\Distributor") - */ - private $distributor; - - /** - * The order number for the part and distributor - * @Column(type="string",nullable=true) - * @var string - */ - private $orderNumber; - - /** - * Defines the packaging unit when ordering a part. Some items can't be ordered in a quantity of just one at - * certain manufacturers. - * - * @Column(type="integer") - * @var integer - */ - private $packagingUnit; - - /** - * Specifies the price of the part. Note that the price - * needs to be per item, not per packaging unit. - * - * @Column(type="decimal",precision=13,scale=4,nullable=true) - * @var float - */ - private $price; - - /** - * Cretes a new part->distributor link. Initializes the packaging unit with a quantity of "1". - * - * @param Part $part The part - * @param Distributor $distributor The distributor - */ - public function __construct () { - $this->setPackagingUnit(1); - } - - /** - * Sets the packaging unit for a specific distributor. - * - * For example, some distributors only sell resistors in packs of 100, so you can't order just one. We use the - * packagingUnit to calculate how many pieces will be delivered once ordered. So if your stock level falls below - * the minimum (example: you would need to order 10 resistors), we suggest that you only order one resistor pack - * instead of 10. - * - * @param int $packagingUnit The amount of items in one package - * @throws \de\RaumZeitLabor\PartKeepr\Part\OutOfRangeException When the packaging unit is less than 1 - */ - public function setPackagingUnit ($packagingUnit) { - $packagingUnit = intval($packagingUnit); - - if ($packagingUnit < 1) { - $exception = new OutOfRangeException(PartKeepr::i18n("Packaging Unit is out of range")); - $exception->setDetail(PartKeepr::i18n("The packaging unit must be 1 or higher")); - throw $exception; - } - - $this->packagingUnit = $packagingUnit; - } - - /** - * Returns the packaging unit - * @return int The packaging unit - */ - public function getPackagingUnit () { - return $this->packagingUnit; - } - - /** - * Sets the part - * @param Part $part The part - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part - * @return Part The part - */ - public function getPart () { - return $this->part; - } - - /** - * Sets the distributor - * @param Distributor $distributor The distributor - */ - public function setDistributor (Distributor $distributor) { - $this->distributor = $distributor; - } - - /** - * Returns the distributor - * @return Distributor The distributor - */ - public function getDistributor () { - return $this->distributor; - } - - /** - * Sets the order number - * @param string $orderNumber The order number - */ - public function setOrderNumber ($orderNumber) { - $this->orderNumber = $orderNumber; - } - - /** - * Returns the order number - * @return string The order number - */ - public function getOrderNumber () { - return $this->orderNumber; - } - - /** - * Sets the price - * @param float $price - */ - public function setPrice ($price) { - echo "/** price set to ".$price." **/"; - $this->price = $price; - } - - /** - * Returns the price - */ - public function getPrice () { - return $this->price; - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "id" => $this->getId(), - "orderNumber" => $this->getOrderNumber(), - "distributor_id" => $this->getDistributor()->getId(), - "distributor_name" => $this->getDistributor()->getName(), - "part_id" => $this->getPart()->getId(), - "part_name" => $this->getPart()->getName(), - "packagingUnit" => $this->getPackagingUnit(), - "price" => $this->getPrice()); - } - - /** - * Deserializes the part manufacturer - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "distributor_id": - $distributor = Distributor::loadById($value); - $this->setDistributor($distributor); - break; - case "orderNumber": - $this->setOrderNumber($value); - break; - case "packagingUnit": - $this->setPackagingUnit($value); - break; - case "price": - $this->setPrice($value); - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartFulltextSearch.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartFulltextSearch.php @@ -1,29 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\FulltextSearch\FulltextSearch; - -/** - * Implements the part fulltext search - */ -class PartFulltextSearch extends FulltextSearch { - /** - * Returns the FQDN of the part entity - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\FulltextSearch.FulltextSearch::getEntityName() - */ - protected function getEntityName () { - return 'de\RaumZeitLabor\PartKeepr\Part\Part'; - } - - /** - * Returns the fields to be searched in - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\FulltextSearch.FulltextSearch::getFields() - */ - protected function getFields () { - return array("comment", "name", "internalPartNumber"); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartImage.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartImage.php @@ -1,50 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Image\Image; - -/** - * Holds a part image - * @Entity - **/ -class PartImage extends Image implements Serializable { - /** - * The part object - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - * @var Part - */ - private $part = null; - - /** - * Creates a new part image instance - */ - public function __construct () { - parent::__construct(Image::IMAGE_PART); - } - - /** - * Sets the part - * @param Part $part The part to set - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part - * @return Part the part - */ - public function getPart () { - return $this->part; - } - - /** - * - * Serializes this part image - * @return array The serialized part imaage - */ - public function serialize () { - return array("id" => $this->getId(), "part_id" => $this->getPart()->getId()); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartManager.php @@ -1,441 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\Logger\Logger; - -use de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter, - Doctrine\ORM\QueryBuilder, - de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter, - de\RaumZeitLabor\PartKeepr\Manager\AbstractManager, - de\RaumZeitLabor\PartKeepr\Unit\Unit, - de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix, - de\RaumZeitLabor\PartKeepr\Part\PartDistributor, - de\RaumZeitLabor\PartKeepr\Part\PartManufacturer, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationManager, - de\RaumZeitLabor\PartKeepr\Part\Part, - Doctrine\ORM\Query, - de\RaumZeitLabor\PartKeepr\PartUnit\PartUnitManager, - de\RaumZeitLabor\PartKeepr\Distributor\Distributor, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintManager, - de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerManager; - -class PartManager extends AbstractManager { - - /** - * Returns the FQCN for the target entity to operate on. - * @return string The FQCN, e.g. de\RaumZeitLabor\PartKeepr\Part - */ - public function getEntityName () { - return 'de\RaumZeitLabor\PartKeepr\Part\Part'; - } - - /** - * 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("name", "description", "averagePrice", "status", "needsReview", "createDate", "id", "stockLevel", - "minStockLevel", "comment", "st.id AS storageLocation_id", "c.categoryPath AS categoryPath", - "st.name as storageLocationName", "f.id AS footprint_id", "f.name AS footprintName", - "c.id AS category", "c.name AS categoryName", "pu.id AS partUnit", "pu.name AS partUnitName", - "pu.is_default AS partUnitDefault" - ); - } - - /** - * Returns the default sort field - * - * @return string The default sort field - */ - public function getDefaultSortField () { - return "dateTime"; - } - - /** - * Appends various join tables to the result set - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Manager.AbstractManager::applyCustomQuery() - */ - protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { - /** - * Pull in additional tables - */ - $qb ->join("q.storageLocation", "st") - ->leftJoin("q.footprint", "f") - ->join("q.category", "c") - ->leftJoin("q.partUnit", "pu"); - - // Apply special handling for non-direct fields in relations, where the frontend has no idea about. - foreach ($filter->getSorters() as $sorter) { - switch ($sorter->getSortField()) { - case "q.categoryPath": - $sorter->setSortField("c.categoryPath"); - break; - case "q.storageLocationName": - $sorter->setSortField("st.name"); - break; - case "q.footprintName": - $sorter->setSortField("f.name"); - break; - default: - break; - } - } - - } - - /** - * Processes the result after it was retrieved. In the default configuration, it returns an array result, or - * if no query fields are specified, it tries to serialize all objects. - */ - protected function getResult (Query $query) { - $result = parent::getResult($query); - - /* Add attachment counts to the result set and re-format the date */ - foreach ($result as $key => $item) { - $dql = "SELECT COUNT(pa) FROM de\RaumZeitLabor\PartKeepr\Part\PartAttachment pa WHERE pa.part = :part"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("part", $item["id"]); - - $result[$key]["attachmentCount"] = $query->getSingleScalarResult(); - - $result[$key]["createDate"] = $result[$key]["createDate"]->format("Y-m-d H:i:s"); - } - - foreach ($result as $key => $item) { - $dql = "SELECT pr.name FROM de\RaumZeitLabor\PartKeepr\Project\Project pr JOIN pr.parts ppart WHERE ppart.part = :part"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("part", $item["id"]); - - $projectNames = array(); - foreach ($query->getArrayResult() as $project) { - $projectNames[] = $project["name"]; - } - - $result[$key]["projects"] = implode(", ", $projectNames); - - } - - foreach ($result as $key => $item) { - $part = Part::loadById($item["id"]); - $result[$key]["attachments"] = $part->serializeChildren($part->getAttachments()); - } - - return $result; - } - - public function addOrUpdatePart ($aParameters) { - - if (!array_key_exists("quantity", $aParameters)) { - $aParameters["quantity"] = 0; - } - - if ($aParameters["part"] !== null) { - try { - $part = $this->getPart($aParameters["part"]); - } catch (\Exception $e) { - $part = new Part(); - $user = SessionManager::getCurrentSession()->getUser(); - - $stock = new StockEntry($part, $aParameters["quantity"], $user); - PartKeepr::getEM()->persist($stock); - } - } else { - $part = new Part(); - - $user = SessionManager::getCurrentSession()->getUser(); - - $stock = new StockEntry($part, $aParameters["quantity"], $user); - PartKeepr::getEM()->persist($stock); - } - - if (array_key_exists("name", $aParameters)) { - $part->setName($aParameters["name"]); - } - - if (array_key_exists("description", $aParameters)) { - $part->setDescription($aParameters["description"]); - } - - if (array_key_exists("minstock", $aParameters)) { - $part->setMinStockLevel($aParameters["minstock"]); - } - - if (array_key_exists("comment", $aParameters)) { - $part->setComment($aParameters["comment"]); - } - - if (array_key_exists("footprint", $aParameters)) { - - if ($aParameters["footprint"] === null) { - $part->setFootprint(null); - } else { - $footprint = FootprintManager::getInstance()->getOrCreateFootprint($aParameters["footprint"]); - $part->setFootprint($footprint); - } - } - - if (array_key_exists("storagelocation", $aParameters)) { - $storageLocation = StorageLocationManager::getInstance()->getOrCreateStorageLocation($aParameters["storagelocation"]); - $part->setStorageLocation($storageLocation); - } - - if (array_key_exists("category", $aParameters)) { - $category = PartCategoryManager::getInstance()->getCategory($aParameters["category"]); - $part->setCategory($category->getNode()); - } - - /* Process linked changes */ - if (array_key_exists("distributorChanges", $aParameters)) { - if (is_array($aParameters["distributorChanges"])) { - $this->processDistributorChanges($part, $aParameters["distributorChanges"]); - } - } - - if (array_key_exists("manufacturerChanges", $aParameters)) { - if (is_array($aParameters["manufacturerChanges"])) { - $this->processManufacturerChanges($part, $aParameters["manufacturerChanges"]); - } - } - - if (array_key_exists("parameterChanges", $aParameters)) { - if (is_array($aParameters["parameterChanges"])) { - $this->processParameterChanges($part, $aParameters["parameterChanges"]); - } - } - - if (array_key_exists("attachmentChanges", $aParameters)) { - if (is_array($aParameters["attachmentChanges"])) { - $this->processAttachmentChanges($part, $aParameters["attachmentChanges"]); - } - } - - if (array_key_exists("partUnit", $aParameters)) { - if ($aParameters["partUnit"] === null || $aParameters["partUnit"] === 0) { - $part->setPartUnit(null); - } else { - $part->setPartUnit(PartUnitManager::getInstance()->getPartUnit($aParameters["partUnit"])); - } - } - - - PartKeepr::getEM()->persist($part); - PartKeepr::getEM()->flush(); - - } - - private function processParameterChanges (Part $part, Array $data) { - if (array_key_exists("updates", $data)) { - foreach ($data["updates"] as $record) { - foreach ($part->getParameters() as $partParameter) { - if ($partParameter->getId() == $record["id"]) { - $partParameter->setName($record["name"]); - $partParameter->setDescription($record["description"]); - $partParameter->setValue($record["value"]); - $partParameter->setSiPrefix(SiPrefix::loadById($record["siprefix_id"])); - $partParameter->setUnit(Unit::loadById($record["unit_id"])); - break; - } - } - } - } - - if (array_key_exists("removals", $data)) { - foreach ($data["removals"] as $record) { - foreach ($part->getParameters() as $partParameter) { - if ($partParameter->getId() == $record["id"]) { - PartKeepr::getEM()->remove($partParameter); - $part->getParameters()->removeElement($partParameter); - break; - } - } - } - } - - if (array_key_exists("inserts", $data)) { - foreach ($data["inserts"] as $record) { - $partParameter = new PartParameter(); - $partParameter->setPart($part); - - $partParameter->setName($record["name"]); - $partParameter->setDescription($record["description"]); - $partParameter->setValue($record["value"]); - $partParameter->setSiPrefix(SiPrefix::loadById($record["siprefix_id"])); - $partParameter->setUnit(Unit::loadById($record["unit_id"])); - - $part->getParameters()->add($partParameter); - } - } - } - - private function processDistributorChanges (Part $part, Array $data) { - if (array_key_exists("updates", $data)) { - foreach ($data["updates"] as $record) { - foreach ($part->getDistributors() as $partDistributor) { - if ($partDistributor->getId() == $record["id"]) { - $partDistributor->setOrderNumber($record["orderNumber"]); - $partDistributor->setDistributor(Distributor::loadById($record["distributor_id"])); - $partDistributor->setPackagingUnit($record["packagingUnit"]); - break; - } - } - } - } - - if (array_key_exists("removals", $data)) { - foreach ($data["removals"] as $record) { - foreach ($part->getDistributors() as $partDistributor) { - if ($partDistributor->getId() == $record["id"]) { - PartKeepr::getEM()->remove($partDistributor); - $part->getDistributors()->removeElement($partDistributor); - break; - } - } - } - } - - if (array_key_exists("inserts", $data)) { - foreach ($data["inserts"] as $record) { - $distributor = new PartDistributor($part, Distributor::loadById($record["distributor_id"])); - $distributor->setOrderNumber($record["orderNumber"]); - $distributor->setPackagingUnit($record["packagingUnit"]); - - $part->getDistributors()->add($distributor); - } - } - } - - private function processManufacturerChanges (Part $part, Array $data) { - if (array_key_exists("updates", $data)) { - foreach ($data["updates"] as $record) { - foreach ($part->getManufacturers() as $partManufacturer) { - if ($partManufacturer->getId() == $record["id"]) { - $partManufacturer->setPartNumber($record["partNumber"]); - $partManufacturer->setManufacturer(Manufacturer::loadById($record["manufacturer_id"])); - break; - } - } - } - } - - if (array_key_exists("removals", $data)) { - foreach ($data["removals"] as $record) { - foreach ($part->getManufacturers() as $partManufacturer) { - if ($partManufacturer->getId() == $record["id"]) { - PartKeepr::getEM()->remove($partManufacturer); - $part->getManufacturers()->removeElement($partManufacturer); - break; - } - } - } - } - - if (array_key_exists("inserts", $data)) { - foreach ($data["inserts"] as $record) { - $manufacturer = new PartManufacturer($part, Manufacturer::loadById($record["manufacturer_id"])); - $manufacturer->setPartNumber($record["partNumber"]); - - $part->getManufacturers()->add($manufacturer); - } - } - } - - private function processAttachmentChanges (Part $part, Array $data) { - if (array_key_exists("updates", $data)) { - foreach ($data["updates"] as $record) { - foreach ($part->getAttachments() as $partAttachment) { - if ($partAttachment->getId() == $record["id"]) { - $partAttachment->setDescription($record["description"]); - break; - } - } - } - } - - if (array_key_exists("removals", $data)) { - foreach ($data["removals"] as $record) { - foreach ($part->getAttachments() as $partAttachment) { - if ($partAttachment->getId() == $record["id"]) { - PartKeepr::getEM()->remove($partAttachment); - $part->getAttachments()->removeElement($partAttachment); - break; - } - } - } - } - - if (array_key_exists("inserts", $data)) { - foreach ($data["inserts"] as $record) { - $attachment = new PartAttachment(); - $attachment->setPart($part); - $attachment->setDescription($record["description"]); - - $file = TempUploadedFile::loadById($record["tmp_id"]); - - $attachment->replace($file->getFilename()); - $attachment->setOriginalFilename($file->getOriginalFilename()); - - $part->getAttachments()->add($attachment); - } - } - } - - public function deletePart ($id) { - $part = PartManager::getInstance()->getPart($id); - - PartKeepr::getEM()->remove($part); - PartKeepr::getEM()->flush(); - } - - public function getPart ($id) { - $part = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\Part\Part", $id); - - return $part; - } - - /** - * Returns the overall part count currently existing. - * @param boolean $withPrice Only consider parts with a price - * @return int The amount of parts in the database - */ - public function getPartCount ($withPrice = false) { - $dql = "SELECT COUNT(p.id) FROM de\RaumZeitLabor\PartKeepr\Part\Part p"; - - if ($withPrice === true) { - $dql .= " WHERE p.averagePrice IS NOT NULL"; - } - - return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); - } - - /** - * Returns the total price for all parts. Only parts with a price are calculated. - * @return float The total price - */ - public function getTotalPrice () { - $dql = "SELECT SUM(p.averagePrice * p.stockLevel) FROM de\RaumZeitLabor\PartKeepr\Part\Part p"; - - return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); - } - - /** - * Returns the average price for all parts. Only parts with a price are calculated. - * @return float The average price - */ - public function getAveragePrice () { - $dql = "SELECT AVG(p.averagePrice) FROM de\RaumZeitLabor\PartKeepr\Part\Part p"; - - return PartKeepr::getEM()->createQuery($dql)->getSingleScalarResult(); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartManufacturer.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartManufacturer.php @@ -1,106 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer; - -/** @Entity **/ -class PartManufacturer extends BaseEntity implements Serializable, Deserializable { - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - */ - private $part; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer") - */ - private $manufacturer; - - /** - * @Column(type="string",nullable=true) - * Enter description here ... - * @var unknown_type - */ - private $partNumber; - - /** - * Sets the part which belongs to this manufacturer entry - * @param Part $part - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part which belongs to this manufacturer entry - */ - public function getPart () { - return $this->part; - } - - /** - * Sets the manufacturer which belongs to this entry - * @param Manufacturer $manufacturer - */ - public function setManufacturer (Manufacturer $manufacturer) { - $this->manufacturer = $manufacturer; - } - - /** - * Returns the manufacturer which belongs to this part - */ - public function getManufacturer () { - return $this->manufacturer; - } - - /** - * Sets the manufacturer-specific part number - * @param string $partNumber - */ - public function setPartNumber ($partNumber) { - $this->partNumber = $partNumber; - } - - /** - * Returns the manufacturer-specific part number - * @return string The part number - */ - public function getPartNumber () { - return $this->partNumber; - } - - /** - * Returns the data of this object in a serialized form. - * @return array The result array - */ - public function serialize () { - return array( - "id" => $this->getId(), - "partNumber" => $this->getPartNumber(), - "manufacturer_id" => $this->getManufacturer()->getId(), - "manufacturer_name" => $this->getManufacturer()->getName(), - "part_id" => $this->getPart()->getId(), - "part_name" => $this->getPart()->getName()); - } - - /** - * Deserializes the part manufacturer - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "manufacturer_id": - $manufacturer = Manufacturer::loadById($value); - $this->setManufacturer($manufacturer); - break; - case "partNumber": - $this->setPartNumber($value); - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartService.php @@ -1,258 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class PartService extends Service implements RestfulService { - public function get () { - if ($this->hasParameter("id")) { - return array("data" => PartManager::getInstance()->getPart($this->getParameter("id"))->serialize()); - } else { - - $filter = new ManagerFilter($this); - $filter->setFilterCallback(array($this, "filterCallback")); - - return PartManager::getInstance()->getList($filter); - } - } - - /** - * Advanced filtering for the list - * @param QueryBuilder The $queryBuilder - */ - public function filterCallback ($queryBuilder) { - - /** - * Applies text-based filtering - */ - if ($this->hasParameter("query") && $this->getParameter("query") != "") { - - $fulltextSearch = new PartFulltextSearch($this->getParameter("query")); - $fulltextSearchResults = $fulltextSearch->query(); - - $queryBuilder->andWhere("q.id IN (".implode(",", $fulltextSearchResults).")"); - - } - - /** - * Applies filtering by the storage location name - */ - if ($this->getParameter("storageLocation") !== null) { - $queryBuilder->andWhere("st.name = :storageLocation"); - $queryBuilder->setParameter("storageLocation", $this->getParameter("storageLocation")); - } - - /** - * Filter by the category id and set the category mode - * - */ - $category = intval($this->getParameter("category", 0)); - - if ($category !== 0) { - /* Fetch all children */ - if ($this->getParameter("categoryScope") == "selected") { - $queryBuilder->andWhere("q.category = :category"); - $queryBuilder->setParameter("category", $category); - } else { - $childs = PartCategoryManager::getInstance()->getChildNodes($category); - $childs[] = $category; - $queryBuilder->andWhere("q.category IN (".implode(",", $childs).")"); - } - } - - /** - * Filter by the stock mode - */ - switch ($this->getParameter("stockMode")) { - case "all": - break; - case "zero": - $queryBuilder->andWhere("q.stockLevel = 0"); - break; - case "nonzero": - $queryBuilder->andWhere("q.stockLevel > 0"); - break; - case "below": - $queryBuilder->andWhere("q.stockLevel < q.minStockLevel"); - break; - } - - /** - * Query by the distributor's order number - */ - if ($this->getParameter("distributorOrderNumber")) { - $queryBuilder->leftJoin("q.distributors", "di"); - $queryBuilder->andWhere("LOWER(di.orderNumber) LIKE :orderNumber"); - $queryBuilder->setParameter("orderNumber", "%".strtolower($this->getParameter("distributorOrderNumber"))."%"); - } - - /** - * Filter by the price - */ - if ($this->getParameter("withoutPrice") === true || $this->getParameter("withoutPrice") === "true") { - $queryBuilder->andWhere("q.averagePrice IS NULL"); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $entity = PartManager::getInstance()->createEntity($this->getParameters()); - - if ($this->getParameter("initialStockLevel") > 0) { - try { - $user = User::loadById($this->getParameter("initialStockLevelUser")); - } catch (\Exception $e) { - $user = SessionManager::getCurrentSession()->getUser(); - } - - $stock = new StockEntry($entity, intval($this->getParameter("initialStockLevel")), $user); - - if ($this->getParameter("initialStockLevelPricePerItem") == true) { - $price = floatval($this->getParameter("initialStockLevelPrice")); - } else { - $price = floatval($this->getParameter("initialStockLevelPrice")) / $this->getParameter("initialStockLevel"); - } - - if ($price != 0) { - $stock->setPrice($price); - } - - PartKeepr::getEM()->persist($stock); - PartKeepr::getEM()->flush(); - - $entity->updateStockLevel(); - PartKeepr::getEM()->flush(); - } - - return array("data" => $entity->serialize()); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - $entity = PartManager::getInstance()->getEntity($this->getParameter("id")); - $entity->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $entity->serialize()); - } - - - public function destroy () { - throw new \Exception("Not yet implemented"); - } - - public function getPartParameterNames () { - $dql = "SELECT pp.name FROM de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter pp GROUP BY pp.name"; - $query = PartKeepr::getEM()->createQuery($dql); - - return array("data" => $query->getArrayResult()); - } - - public function movePart () { - $this->requireParameter("targetCategory"); - - if ($this->getParameter("parts", false) !== false) { - /* We are moving multiple parts */ - foreach ($this->getParameter("parts") as $part) { - $part = Part::loadById($part); - $category = PartCategory::loadById($this->getParameter("targetCategory")); - - $part->setCategory($category); - } - } else { - $part = Part::loadById($this->getParameter("part")); - $category = PartCategory::loadById($this->getParameter("targetCategory")); - - $part->setCategory($category); - - } - - PartKeepr::getEM()->flush(); - } - - public function addStock () { - $part = PartManager::getInstance()->getPart($this->getParameter("part")); - - $user = SessionManager::getCurrentSession()->getUser(); - - $stock = new StockEntry($part, intval($this->getParameter("stock")), $user); - - $price = floatval($this->getParameter("price")); - - if ($price != 0) { - $stock->setPrice($price); - } - - PartKeepr::getEM()->persist($stock); - PartKeepr::getEM()->flush(); - - $part->updateStockLevel(); - - PartKeepr::getEM()->flush(); - - return array("data" => $part->serialize()); - } - - public function deleteStock () { - $part = PartManager::getInstance()->getPart($this->getParameter("part")); - - $user = SessionManager::getCurrentSession()->getUser(); - - $stock = new StockEntry($part, 0-intval($this->getParameter("stock")), $user); - - PartKeepr::getEM()->persist($stock); - PartKeepr::getEM()->flush(); - - $part->updateStockLevel(); - - PartKeepr::getEM()->flush(); - - return array("data" => $part->serialize()); - } - - public function massDeleteStock () { - $data = $this->getParameter("removals"); - - $updateStockLevels = array(); - - foreach ($data as $item) { - $part = PartManager::getInstance()->getPart($item["part"]); - $user = SessionManager::getCurrentSession()->getUser(); - - $stock = new StockEntry($part, 0-intval($item["amount"]), $user); - $stock->setComment($item["comment"]); - PartKeepr::getEM()->persist($stock); - - $updateStockLevels[$item["part"]] = $part; - } - - PartKeepr::getEM()->flush(); - - foreach ($updateStockLevels as $part) { - $part->updateStockLevel(); - } - - PartKeepr::getEM()->flush(); - return array(); - } - - public function deletePart () { - PartManager::getInstance()->deletePart($this->getParameter("part")); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartUnit.php b/src/backend/de/RaumZeitLabor/PartKeepr/Part/PartUnit.php @@ -1,137 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Part; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Exceptions\OutOfRangeException; - - -/** @Entity **/ -class PartUnit extends BaseEntity implements Serializable, Deserializable { - /** - * Defines the name of the unit - * @Column - * @var string - */ - private $name; - - /** - * Defines the short name of the unit - * @Column - * @var string - */ - private $shortName; - - /** - * Defines if the unit is default or not. - * - * @Column(type="boolean") - * @var boolean - */ - private $is_default; - - /** - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part",mappedBy="partUnit") - */ - private $parts; - - - /** - * Creates a new part unit. - * - * Sets the default to false. - */ - public function __construct () { - $this->setDefault(false); - } - - /** - * Sets the name for this unit - * @param string $name The name for this unit - * @return nothing - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name for this unit - * @param none - * @return string The name for this unit - */ - public function getName () { - return $this->name; - } - - /** - * Sets the short name for this unit. - * - * Short names are used for list views (e.g. if your unit name is "metres", your short name could be "m") - * @param string $shortName The short name - * @return nothing - */ - public function setShortName ($shortName) { - $this->shortName = $shortName; - } - - /** - * Returns the short name for this unit - * @param none - * @return string The short name for this unit - */ - public function getShortName () { - return $this->shortName; - } - - /** - * Defines if the unit is default or not. - * @param boolean $default True if the unit is default, false otherwise - */ - public function setDefault ($default) { - $this->is_default = (bool)$default; - } - - /** - * Returns if the unit is default or not - * @param none - * @return boolean True if the unit is default, false for not - */ - public function getDefault () { - return $this->is_default; - } - - /** - * Serializes the object and returns it as array, suitable - * to process via json_encode. - * @param none - * @return array An array containing the object information - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "shortName" => $this->getShortName(), - "default" => $this->getDefault() - ); - } - - /** - * Deserializes the manufacturer - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "shortName": - $this->setShortName($value); - break; - } - } - } -} - - \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategory.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategory.php @@ -1,14 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartCategory; - -use de\RaumZeitLabor\PartKeepr\Category\AbstractCategory; - -/** - * @Entity - * @Table(indexes={@index(columns={"lft"}),@index(columns={"rgt"})}) - * The entity for our part categories - * - */ -class PartCategory extends AbstractCategory { - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategoryManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategoryManager.php @@ -1,42 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartCategory; - -use de\RaumZeitLabor\PartKeepr\Category\AbstractCategoryManager; -use DoctrineExtensions\NestedSet\NodeWrapper; -use de\RaumZeitLabor\PartKeepr\Util\SerializableException; -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -class PartCategoryManager extends AbstractCategoryManager { - protected $categoryClass = "de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory"; - - /** - * Deletes the given category ID. - * @param $id int The category id to delete - * @throws CategoryNotFoundException If the category wasn't found - */ - public function deleteCategory ($id) { - $category = $this->getCategory($id); - - try { - - if ($category->hasChildren()) { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains other categories."), $category->getNode()->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains other categories. Please move the categories or delete them first."), $category->getNode()->getName())); - - throw $exception; - } - - parent::deleteCategory($id); - } catch (\PDOException $e) { - if ($e->getCode() == "23000") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Category '%s' contains parts."), $category->getNode()->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to delete the category '%s', but it still contains parts. Please move the parts to another category."), $category->getNode()->getName())); - - throw $exception; - } else { - throw $e; - } - } - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategoryService.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartCategory/PartCategoryService.php @@ -1,9 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartCategory; - -use de\RaumZeitLabor\PartKeepr\Category\AbstractCategoryService; - -class PartCategoryService extends AbstractCategoryService { - protected $categoryManagerClass = "de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager"; - protected $categoryClass = "de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory"; -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartDistributor/PartDistributorManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartDistributor/PartDistributorManager.php @@ -1,74 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartDistributor; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\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("de\RaumZeitLabor\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("de\RaumZeitLabor\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("de\RaumZeitLabor\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/de/RaumZeitLabor/PartKeepr/PartDistributor/PartDistributorService.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartDistributor/PartDistributorService.php @@ -1,84 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\ManufacturerICLogo; - -use de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\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/de/RaumZeitLabor/PartKeepr/PartKeepr.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php @@ -1,434 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr; - -use Doctrine\Common\ClassLoader, - de\RaumZeitLabor\PartKeepr\SystemNotice\SystemNoticeManager, - Doctrine\ORM\Configuration, - Doctrine\ORM\EntityManager, - de\RaumZeitLabor\PartKeepr\Util\Configuration as PartKeeprConfiguration; - - - -class PartKeepr { - /** - * - * Contains the doctrine entity manager. - * @var Doctrine\ORM\EntityManager - */ - private static $entityManager = null; - - /** - * 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. - * @return nothing - */ - public static function initialize ($environment = null) { - self::initializeClassLoaders(); - self::initializeConfig($environment); - self::initializeDoctrine(); - } - - /** - * Initializes the doctrine class loader and sets up the - * directories. - * - * @param none - * @return nothing - */ - public static function initializeClassLoaders() { - require_once 'Doctrine/Common/ClassLoader.php'; - - - $classLoader = new ClassLoader('de\RaumZeitLabor\PartKeepr', dirname(dirname(dirname(__DIR__)))); - $classLoader->register(); - - $classLoader = new ClassLoader('Doctrine\ORM'); - $classLoader->register(); - - $classLoader = new ClassLoader("Doctrine\DBAL\Migrations", dirname(dirname(dirname(dirname(dirname(__DIR__))))) ."/3rdparty/doctrine-migrations/lib"); - $classLoader->register(); - - $classLoader = new ClassLoader('Doctrine\DBAL'); - $classLoader->register(); - - $classLoader = new ClassLoader('Doctrine\Common'); - $classLoader->register(); - - $classLoader = new ClassLoader('Symfony', 'Doctrine'); - $classLoader->register(); - - $classLoader = new ClassLoader("DoctrineExtensions\NestedSet", dirname(dirname(dirname(dirname(dirname(__DIR__))))) ."/3rdparty/doctrine2-nestedset/lib"); - $classLoader->register(); - - - } - - /** - * 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. - * @return nothing - */ - public static function initializeConfig ($environment = null) { - if ($environment != null) { - include(dirname(dirname(dirname(dirname(dirname(__DIR__)))))."/config-$environment.php"); - } else { - include(dirname(dirname(dirname(dirname(dirname(__DIR__)))))."/config.php"); - } - - // 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 (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"] - ); - - } - } - - /** - * Initializes the doctrine framework and - * sets all required configuration options. - * - * @param none - * @return nothing - */ - public static function initializeDoctrine () { - $config = new Configuration; - - $driverImpl = $config->newDefaultAnnotationDriver( - array(__DIR__) - ); - $config->setMetadataDriverImpl($driverImpl); - - $connectionOptions = PartKeepr::createConnectionOptionsFromConfig(); - - if (extension_loaded("apc")) { - $cache = new \Doctrine\Common\Cache\ApcCache(); - } else { - $cache = new \Doctrine\Common\Cache\ArrayCache(); - } - - $config->setMetadataCacheImpl($cache); - - $config->setQueryCacheImpl($cache); - - $config->setProxyDir(dirname(dirname(dirname(dirname(dirname(__DIR__))))) . '/data/proxies'); - $config->setProxyNamespace('Proxies'); - $config->setEntityNamespaces(self::getEntityClasses()); - $config->setAutoGenerateProxyClasses(false); - - if (PartKeeprConfiguration::getOption("partkeepr.database.echo_sql_log", false) === true) { - $logger = new \Doctrine\DBAL\Logging\EchoSQLLogger(); - $config->setSQLLogger($logger); - } - - self::$entityManager = EntityManager::create($connectionOptions, $config); - } - - public static function createConnectionOptionsFromConfig () { - $connectionOptions = array(); - - $driver = PartKeeprConfiguration::getOption("partkeepr.database.driver"); - - switch ($driver) { - case "pdo_mysql": - case "pdo_pgsql": - case "pdo_oci": - case "oci8": - case "pdo_sqlsrv": - $connectionOptions["driver"] = $driver; - $connectionOptions["dbname"] = PartKeeprConfiguration::getOption("partkeepr.database.dbname", "partkeepr"); - $connectionOptions["user"] = PartKeeprConfiguration::getOption("partkeepr.database.username", "partkeepr"); - $connectionOptions["password"] = PartKeeprConfiguration::getOption("partkeepr.database.password", "partkeepr"); - $connectionOptions["charset"] = "utf8"; - /** - * Compatibility with older configuration files. We check for the key "hostname" as well as "host". - */ - if (PartKeeprConfiguration::getOption("partkeepr.database.hostname", null) !== null) { - $connectionOptions["host"] = PartKeeprConfiguration::getOption("partkeepr.database.hostname"); - } else { - $connectionOptions["host"] = PartKeeprConfiguration::getOption("partkeepr.database.host", "localhost"); - } - - - if (PartKeeprConfiguration::getOption("partkeepr.database.port") !== null) { - $connectionOptions["port"] = PartKeeprConfiguration::getOption("partkeepr.database.port"); - } - - if (PartKeeprConfiguration::getOption("partkeepr.database.mysql_socket", null) !== null) { - $connectionOptions["unix_socket"] = PartKeeprConfiguration::getOption("partkeepr.database.mysql_socket"); - } - break; - case "pdo_sqlite": - $connectionOptions["driver"] = $driver; - $connectionOptions["user"] = PartKeeprConfiguration::getOption("partkeepr.database.username", "partkeepr"); - $connectionOptions["password"] = PartKeeprConfiguration::getOption("partkeepr.database.password", "partkeepr"); - $connectionOptions["path"] = PartKeeprConfiguration::getOption("partkeepr.database.sqlite_path", PartKeepr::getRootDirectory() . "/data/partkeepr.sqlite"); - break; - default: - throw new \Exception(sprintf("Unknown driver %s", $driver)); - } - - return $connectionOptions; - } - - /** - * Returns the EntityManager. Shortcut for getEntityManager(). - * @return \Doctrine\ORM\EntityManager The EntityManager - */ - public static function getEM () { - return self::getEntityManager(); - } - - public static function getRootDirectory () { - return dirname(dirname(dirname(dirname(dirname(__DIR__))))); - } - - /** - * Returns the EntityManager. - * @return Doctrine\ORM\EntityManager The EntityManager - */ - public static function getEntityManager () { - if (!self::$entityManager instanceof EntityManager) { - throw new Exception("No EntityManager found. Make sure you called initializeDoctrine() or initialize()."); - } - return self::$entityManager; - } - - /** - * 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( - 'de\RaumZeitLabor\PartKeepr\User\User', - 'de\RaumZeitLabor\PartKeepr\Session\Session', - - 'de\RaumZeitLabor\PartKeepr\Footprint\Footprint', - 'de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage', - 'de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment', - 'de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory', - - 'de\RaumZeitLabor\PartKeepr\Part\Part', - 'de\RaumZeitLabor\PartKeepr\Part\PartUnit', - 'de\RaumZeitLabor\PartKeepr\Part\PartManufacturer', - 'de\RaumZeitLabor\PartKeepr\Part\PartDistributor', - 'de\RaumZeitLabor\PartKeepr\Part\PartImage', - 'de\RaumZeitLabor\PartKeepr\Part\PartAttachment', - 'de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory', - - 'de\RaumZeitLabor\PartKeepr\Project\Project', - 'de\RaumZeitLabor\PartKeepr\Project\ProjectPart', - 'de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment', - - 'de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation', - 'de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationImage', - - 'de\RaumZeitLabor\PartKeepr\Stock\StockEntry', - - 'de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer', - 'de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo', - - 'de\RaumZeitLabor\PartKeepr\Distributor\Distributor', - - 'de\RaumZeitLabor\PartKeepr\Image\Image', - 'de\RaumZeitLabor\PartKeepr\Image\CachedImage', - 'de\RaumZeitLabor\PartKeepr\TempImage\TempImage', - - 'de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile', - - 'de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshot', - 'de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshotUnit', - 'de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix', - 'de\RaumZeitLabor\PartKeepr\Unit\Unit', - 'de\RaumZeitLabor\PartKeepr\PartParameter\PartParameter', - - 'de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDay', - 'de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDayHistory', - 'de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference', - 'de\RaumZeitLabor\PartKeepr\SystemNotice\SystemNotice', - 'de\RaumZeitLabor\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; - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartKeeprVersion.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartKeeprVersion.php @@ -1,15 +0,0 @@ -<?php -namespace de\RaumZeitLabor\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/de/RaumZeitLabor/PartKeepr/PartParameter/PartParameter.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartParameter/PartParameter.php @@ -1,247 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartParameter; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, -de\RaumZeitLabor\PartKeepr\Util\Exceptions\OutOfRangeException, -de\RaumZeitLabor\PartKeepr\Unit\Unit, -de\RaumZeitLabor\PartKeepr\Part\Part, -de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix; - - -/** - * This object represents a parameter. Each parameter can have an unit (defined by the class "Unit") associated with - * a numeric value. - * - * @Entity @HasLifecycleCallbacks - **/ -class PartParameter { - /** - * @Id @Column(type="integer") - * @GeneratedValue(strategy="AUTO") - * @var integer - */ - private $id; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - * The part this parameter is bound to - * @var Part - */ - private $part; - - /** - * The name of the parameter (e.g. Resistance, Voltage) - * @Column(type="string") - * @var string - */ - private $name; - - /** - * A description for this parameter - * @Column(type="string") - * @var string - */ - private $description; - - /** - * The unit for this type. May be null. - * - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Unit\Unit") - * @var Unit - */ - private $unit; - - /** - * The value of the unit. Together with the prefix, it becomes the actual value. - * - * Example: If you have 10µ, the value field will contain "10", the prefix object is linked to the SiPrefix - * representing "µ" and the rawValue field will contain 0.000001 - * @Column(type="float") - * @var float - */ - private $value; - - /** - * The SiPrefix of the unit - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix") - * @var object - */ - private $siPrefix; - - /** - * The raw value of the unit. - * @Column(type="float") - * @var float - */ - private $rawValue; - - /** - * Sets the name for this parameter - * @param string $name The name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name for this parameter - * @return string The name for this parameter - */ - public function getName () { - return $this->name; - } - - /** - * Sets the description for this parameter - * @param string $description The description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * Sets the unit - * @param Unit $unit The unit to set - */ - public function setUnit (Unit $unit = null) { - $this->unit = $unit; - } - - /** - * Returns the unit - * @return Unit the unit - */ - public function getUnit () { - return $this->unit; - } - - /** - * Sets the part - * @param Part $part The part to set - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part - * @return Part the part - */ - public function getPart () { - return $this->part; - } - - /** - * Sets the value - * @param float $value The value to set - */ - public function setValue ($value) { - $this->value = $value; - - $this->recalculateRawValue(); - } - - /** - * Returns the value - * @return float The value - */ - public function getValue () { - return $this->value; - } - - /** - * Sets the si prefix for this parameter - * @param SiPrefix $prefix The prefix to set, or null - */ - public function setSiPrefix (SiPrefix $prefix = null) { - $this->siPrefix = $prefix; - - $this->recalculateRawValue(); - } - - /** - * Returns the si prefix for this parameter - * @return SiPrefix the si prefix or null - */ - public function getSiPrefix () { - return $this->siPrefix; - } - - /** - * Returns the ID for this object. - * @param none - * @return int The ID for this object - */ - public function getId () { - return $this->id; - } - - private function recalculateRawValue () { - if (is_object($this->getSiPrefix())) { - $power = $this->getSiPrefix()->getPower(); - } else { - $power = 0; - } - - $this->rawValue = $this->getValue() * pow(10, $power); - } - - /** - * Returns the data of this object in a serialized form. - * @return array The result array - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription(), - "value" => $this->getValue(), - "part_id" => $this->getPart()->getId(), - "siprefix_id" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getId() : null, - "prefixedValue" => array( - /* We duplicate most data because of strange ExtJS stuff... */ - "value" => $this->getValue(), - "power" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getPower() : 0, - "symbol" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getSymbol() : "", - "siprefix_id" => is_object($this->getSiPrefix()) ? $this->getSiPrefix()->getId() : null - ), - "unit_id" => is_object($this->getUnit()) ? $this->getUnit()->getId() : null - ); - } - - /** - * Deserializes the part parameter - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "description": - $this->setDescription($value); - break; - case "value": - $this->setValue($value); - break; - case "siprefix_id": - $prefix = SiPrefix::loadById($value); - $this->setSiPrefix($prefix); - break; - case "unit_id": - $unit = Unit::loadById($value); - $this->setUnit($unit); - break; - } - } - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitManager.php @@ -1,106 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartUnit; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Part\PartUnit, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, - de\RaumZeitLabor\PartKeepr\PartUnit\Exceptions\PartUnitNotFoundException; - -class PartUnitManager extends Singleton { - public function getPartUnits ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st.id, st.name, st.shortName, st.is_default AS default")->from("de\RaumZeitLabor\PartKeepr\Part\PartUnit","st"); - - if ($filter != "") { - $qb = $qb->where("LOWER(st.name) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - foreach ($result as $key => $row) { - foreach ($row as $rowkey => $column) { - if ($rowkey == "default") { - if ($column == 0) { - $result[$key][$rowkey] = false; - } else { - $result[$key][$rowkey] = true; - } - } - } - } - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\Part\PartUnit","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - public function getPartUnit ($id) { - $partUnit = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\Part\PartUnit", $id); - - if ($partUnit) { - return $partUnit; - } else { - throw new PartUnitNotFoundException(); - } - } - - public function deletePartUnit ($id) { - $partUnit = $this->getPartUnit($id); - - PartKeepr::getEM()->remove($partUnit); - PartKeepr::getEM()->flush(); - } - - /** - * Returns the default part unit for this system - * - * @param none - * @return PartUnit The default part unit for this system - */ - public function getDefaultPartUnit () { - $dql = 'SELECT pu FROM de\RaumZeitLabor\PartKeepr\Part\PartUnit pu WHERE pu.is_default = :default'; - return PartKeepr::getEM()->createQuery($dql)->setParameter("default", true)->getSingleResult(); - } - - public function setDefaultPartUnit ($id) { - PartKeepr::getEM()->beginTransaction(); - - $dql = 'UPDATE de\RaumZeitLabor\PartKeepr\Part\PartUnit pu SET pu.is_default = :default WHERE pu.id = :id'; - PartKeepr::getEM()->createQuery($dql)->setParameter("id", $id)->setParameter("default", true, \PDO::PARAM_BOOL)->execute(); - - $dql = 'UPDATE de\RaumZeitLabor\PartKeepr\Part\PartUnit pu SET pu.is_default = :default WHERE pu.id != :id'; - PartKeepr::getEM()->createQuery($dql)->setParameter("id", $id)->setParameter("default", false, \PDO::PARAM_BOOL)->execute(); - - PartKeepr::getEM()->commit(); - } - - public function getUnitCounts () { - $dql = 'SELECT SUM(p.stockLevel) AS stockLevel, pu.id AS puid FROM de\RaumZeitLabor\PartKeepr\Part\PartUnit pu LEFT JOIN pu.parts p GROUP BY pu.id'; - - $result = PartKeepr::getEM()->createQuery($dql)->getResult(); - - return $result; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitService.php b/src/backend/de/RaumZeitLabor/PartKeepr/PartUnit/PartUnitService.php @@ -1,72 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\PartUnit; -use de\RaumZeitLabor\PartKeepr\Service\RestfulService; - -use de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\PartUnit, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class PartUnitService extends Service implements RestfulService { - public function get () { - if ($this->hasParameter("id")) { - return array("data" => PartUnitManager::getInstance()->getPartUnit($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "name", - "direction" => "ASC"); - } - return PartUnitManager::getInstance()->getPartUnits( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - public function create () { - $this->requireParameter("name"); - - $partUnit = new PartUnit; - $partUnit->deserialize($this->getParameters()); - - PartKeepr::getEM()->persist($partUnit); - PartKeepr::getEM()->flush(); - - return array("data" => $partUnit->serialize()); - } - - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - - $partUnit = PartUnitManager::getInstance()->getPartUnit($this->getParameter("id")); - $partUnit->deserialize($this->getParameters()); - PartKeepr::getEM()->flush(); - - return array("data" => $partUnit->serialize()); - - } - - public function destroy () { - $this->requireParameter("id"); - - PartUnitManager::getInstance()->deletePartUnit($this->getParameter("id")); - - return array("data" => null); - } - - public function setDefault () { - $this->requireParameter("id"); - - $partUnit = PartUnitManager::getInstance()->setDefaultPartUnit($this->getParameter("id")); - - return array("data" => null); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Ping/PingService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Ping/PingService.php @@ -1,19 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Ping; -use de\RaumZeitLabor\PartKeepr\Service\AnonService; - -use de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class PingService extends AnonService { - /** - * Simple test call to verify if the service layer is reachable. - * - * This is used for the PartKeeprMobile client to verify if the URL - * is entered correctly. - */ - public function ping () { - return "pong"; - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Project/Project.php b/src/backend/de/RaumZeitLabor/PartKeepr/Project/Project.php @@ -1,161 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Project; - -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity; - -/** - * Represents a part in the database. The heart of our project. Handle with care! - * @Entity **/ -class Project extends BaseEntity implements Serializable, Deserializable { - /** - * Specifies the name of the project - * @Column(type="string") - */ - private $name; - - /** - * Specifies the user this project belongs to - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\User\User") - */ - private $user; - - /** - * Holds the parts needed for this project - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Project\ProjectPart",mappedBy="project",cascade={"persist", "remove"}) - * @var ArrayCollection - */ - private $parts; - - /** - * Holds the description of this project - * @Column(type="string",nullable=true) - * @var string - */ - private $description; - - /** - * Holds the project attachments - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment",mappedBy="project",cascade={"persist", "remove"}) - * @var ProjectAttachment - */ - private $attachments; - - - /** - * Constructs a new project - */ - public function __construct () { - $this->parts = new \Doctrine\Common\Collections\ArrayCollection(); - $this->attachments = new \Doctrine\Common\Collections\ArrayCollection(); - } - - /** - * Sets the user for this project - * @param User $user - */ - public function setUser (User $user) { - $this->user = $user; - } - - /** - * Gets the user for this project - * @return User - */ - public function getUser () { - return $this->user; - } - - /** - * Sets the name for this project - * @param string $name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of this project - */ - public function getName () { - return $this->name; - } - - /** - * Sets the description of this project - * @param string $description The description to set - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description of this project - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * Returns the parts array - * @return ArrayCollection An array of ProjectPart objects - */ - public function getParts () { - return $this->parts; - } - - /** - * Returns the attachments for this project - * @return ArrayCollection The attachments - */ - public function getAttachments () { - return $this->attachments; - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "description" => $this->getDescription(), - "parts" => $this->serializeChildren($this->getParts()), - "attachments" => $this->serializeChildren($this->getAttachments()) - ); - } - - /** - * Deserializes the project - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "description": - $this->setDescription($value); - break; - case "parts": - $this->deserializeChildren($value, $this->getParts(), "de\RaumZeitLabor\PartKeepr\Project\ProjectPart"); - foreach ($this->getParts() as $part) { - $part->setProject($this); - } - break; - case "attachments": - $this->deserializeChildren($value, $this->getAttachments(), "de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment"); - foreach ($this->getAttachments() as $attachment) { - $attachment->setProject($this); - } - break; - } - } - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectAttachment.php b/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectAttachment.php @@ -1,101 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Project; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\UploadedFile\UploadedFile; - -/** - * Holds a project attachment - * @Entity - **/ -class ProjectAttachment extends UploadedFile implements Serializable, Deserializable { - /** - * The description of this attachment - * @Column(type="text") - * @var string - */ - private $description; - - /** - * Creates a new project attachment - */ - public function __construct () { - parent::__construct(); - $this->setType("ProjectAttachment"); - } - /** - * The project object - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Project\Project") - * @var Project - */ - private $project = null; - - /** - * Sets the project - * @param Project $project The project to set - */ - public function setProject (Project $project) { - $this->project = $project; - } - - /** - * Returns the roject - * @return Project the project - */ - public function getProject () { - return $this->project; - } - - /** - * Sets the description for this attachment - * @param string $description The attachment description - */ - public function setDescription ($description) { - $this->description = $description; - } - - /** - * Returns the description for this attachment - * @return string The description - */ - public function getDescription () { - return $this->description; - } - - /** - * - * Serializes this project attachment - * @return array The serialized project attachment - */ - public function serialize () { - return array( - "id" => $this->getId(), - "project_id" => $this->getProject()->getId(), - "originalFilename" => $this->getOriginalFilename(), - "mimetype" => $this->getMimetype(), - "extension" => $this->getExtension(), - "size" => $this->getSize(), - "description" => $this->getDescription()); - } - - /** - * Deserializes the project attachment - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - if (array_key_exists("id", $parameters)) { - if (substr($parameters["id"], 0, 4) === "TMP:") { - $this->replaceFromTemporaryFile($parameters["id"]); - } - } - - foreach ($parameters as $key => $value) { - switch ($key) { - case "description": - $this->setDescription($value); - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectManager.php @@ -1,33 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Project; - -use de\RaumZeitLabor\PartKeepr\Manager\AbstractManager, - de\RaumZeitLabor\PartKeepr\Project\Project, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class ProjectManager extends AbstractManager { - /** - * Returns the FQCN for the target entity to operate on. - * @return string The FQCN, e.g. de\RaumZeitLabor\PartKeepr\Part - */ - public function getEntityName () { - return 'de\RaumZeitLabor\PartKeepr\Project\Project'; - } - - /** - * 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", "name", "description"); - } - - /** - * Returns the default sort field - * - * @return string The default sort field - */ - public function getDefaultSortField () { - return "name"; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectPart.php b/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectPart.php @@ -1,136 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Project; - -use de\RaumZeitLabor\PartKeepr\Part\Part, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity; - -/** - * Represents a part in the database. The heart of our project. Handle with care! - * @Entity **/ -class ProjectPart extends BaseEntity implements Serializable, Deserializable { - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - */ - private $part; - - /** - * Specifies the amount of parts - * @Column(type="integer") - */ - private $quantity; - - /** - * Specifies the project which belongs to this project part - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Project\Project") - */ - private $project; - - /** - * Specifies the remarks for this entry - * @Column(type="string",nullable=true) - */ - private $remarks; - - /** - * Sets the part which belongs to this entry - * @param Part $part - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part which belongs to this entry - * @return Part - */ - public function getPart () { - return $this->part; - } - - /** - * Sets the quantity for this entry - * @param int $quantity - */ - public function setQuantity ($quantity) { - $this->quantity = intval($quantity); - } - - /** - * Returns the quantity for this project - * @return int the amount of parts needed - */ - public function getQuantity () { - return $this->quantity; - } - - /** - * Sets the project assigned to this entry - * @param Project $project - */ - public function setProject (Project $project) { - $this->project = $project; - } - - /** - * Returns the project assigned to this entry - * @return Project - */ - public function getProject () { - return $this->project; - } - - /** - * Sets the remarks for this entry - * @param string $remarks - */ - public function setRemarks ($remarks) { - $this->remarks = $remarks; - } - - /** - * Returns the remarks for this entry - * @return string - */ - public function getRemarks () { - return $this->remarks; - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "id" => $this->getId(), - "quantity" => $this->getQuantity(), - "part_id" => is_object($this->getPart()) ? $this->getPart()->getId() : 0, - "part_name" => is_object($this->getPart()) ? $this->getPart()->getName() : 0, - "project_id" => $this->getProject()->getId(), - "remarks" => $this->getRemarks() - ); - } - - /** - * Deserializes the project - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "remarks": - $this->setRemarks($value); - break; - case "quantity": - $this->setQuantity($value); - break; - case "part_id": - $part = Part::loadById($value); - $this->setPart($part); - break; - } - } - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Project/ProjectService.php @@ -1,64 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Project; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Project\ProjectManager, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter; - -class ProjectService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return array("data" => ProjectManager::getInstance()->getEntity($this->getParameter("id"))->serialize()); - } else { - $parameters = new ManagerFilter($this); - $parameters->setFilterField("name"); - return ProjectManager::getInstance()->getList($parameters); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $this->requireParameter("name"); - - $entity = ProjectManager::getInstance()->createEntity($this->getParameters()); - - return array("data" => $entity->serialize()); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - $entity = ProjectManager::getInstance()->getEntity($this->getParameter("id")); - $entity->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $entity->serialize()); - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - ProjectManager::getInstance()->deleteEntity($this->getParameter("id")); - - return array("data" => null); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/ProjectAttachment/ProjectAttachmentManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/ProjectAttachment/ProjectAttachmentManager.php @@ -1,68 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\ProjectAttachment; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Project\Project, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class ProjectAttachmentManager extends Singleton { - /** - * Returns a list of project attachments - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter The project id - */ - public function getProjectAttachments ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st")->from("de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment","st") - ->leftJoin('st.project', "fp"); - - if ($filter != "") { - $project = Project::loadById($filter); - $qb = $qb->where("st.project = :project"); - $qb->setParameter("project", $project); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("st.project = :project"); - $totalQueryBuilder->setParameter("project", $project); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - $aData = array(); - foreach ($result as $item) { - $aData[] = $item->serialize(); - } - return array("data" => $aData, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Returns a project attachment by id - * @param int $id The project attachment id - */ - public function getProjectAttachment ($id) { - return ProjectAttachment::loadById($id); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/ProjectAttachment/ProjectAttachmentService.php b/src/backend/de/RaumZeitLabor/PartKeepr/ProjectAttachment/ProjectAttachmentService.php @@ -1,102 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\ProjectAttachment; - -use de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment, - de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Project\Project, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class ProjectAttachmentService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return ProjectAttachmentManager::getInstance()->getProjectAttachment($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"] == "project_id") { - if (array_key_exists("value", $item)) { - $filter = $item["value"]; - } - } - } - } - } - return ProjectAttachmentManager::getInstance()->getProjectAttachments( - $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); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - $this->requireParameter("tmp_id"); - $this->requireParameter("project_id"); - - $tmpImage = TempUploadedFile::loadById($this->getParameter("tmp_id")); - - $file = new ProjectAttachment(); - - $project = Project::loadById($this->getParameter("project_id")); - - $file->setProject($project); - $file->replace($tmpImage->getFilename()); - $file->setOriginalFilename($tmpImage->getOriginalFilename()); - $file->setDescription($this->getParameter("description")); - PartKeepr::getEM()->persist($file); - PartKeepr::getEM()->flush(); - - return $file->serialize(); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - $this->requireParameter("id"); - - $file = ProjectAttachment::loadById($this->getParameter("id")); - - PartKeepr::getEM()->remove($file); - PartKeepr::getEM()->flush(); - - return array("data" => null); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/ProjectReport/ProjectReportService.php b/src/backend/de/RaumZeitLabor/PartKeepr/ProjectReport/ProjectReportService.php @@ -1,97 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\ProjectReport; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Project\ProjectManager, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\Part, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter; - -class ProjectReportService extends Service implements RestfulService { - /** - * Returns a project report. - * - * The input format is an array with the following keys per entry: - * - project: The project ID - * - amount: Specifies how many copies of the project need to be reported - * - * The output format is an array which contains the following keys: - * - quantity: The overall quantity of parts needed (for a specific part) - * - part: The serialized part entity - * - storageLocation_name: The storage location name - * - available: The overall amount of available parts - * - sum_order: Always set to 0 because calculation happens in the frontend - * - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - $reports = json_decode($this->getParameter("reports"), true); - - $aPartResults = array(); - - // Loop over all reports and calculate the overall quantities - foreach ($reports as $report) { - $dql = "SELECT pp.quantity, pro.name AS projectname, pp.remarks, p.id FROM "; - $dql .= "de\RaumZeitLabor\PartKeepr\Project\ProjectPart pp JOIN pp.part p "; - $dql .= "JOIN pp.project pro WHERE pp.project = :project"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("project", $report["project"]); - - foreach ($query->getArrayResult() as $result) { - $part = Part::loadById($result["id"]); - - if (array_key_exists($result["id"], $aPartResults)) { - // Only update the quantity of the part - $aPartResults[$result["id"]]["quantity"] += $result["quantity"] * $report["amount"]; - $aPartResults[$result["id"]]["projects"][] = $result["projectname"]; - - if ($result["remarks"] != "") { - $aPartResults[$result["id"]]["remarks"][] = $result["projectname"]. ": " .$result["remarks"]; - } - } else { - // Create a full resultset - $aPartResults[$result["id"]] = array( - "quantity" => $result["quantity"] * $report["amount"], - "part" => array("response" => array("totalCount" => 1, "data" => $part->serialize())), - "storageLocation_name" => $part->getStorageLocation()->getName(), - "available" => $part->getStockLevel(), - "sum_order" => 0, - "projects" => array($result["projectname"]), - "remarks" => array() - ); - - if ($result["remarks"] != "") { - $aPartResults[$result["id"]]["remarks"] = array($result["projectname"]. ": " .$result["remarks"]); - } - } - } - } - - $aFinalResult = array(); - - // Iterate over all results and calculate how many parts are missing - foreach ($aPartResults as $key => $partResult) { - $missing = $partResult["quantity"] - $partResult["available"]; - - if ($missing < 0) { - $missing = 0; - } - - $partResult["missing"] = $missing; - $partResult["remarks"] = implode(", ", $partResult["remarks"]); - $partResult["projects"] = implode(", ", $partResult["projects"]); - - $aFinalResult[] = $partResult; - } - - return array("data" => $aFinalResult); - } - - public function create () {} - - public function update () {} - - public function destroy () {} -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/REST/ApplicationController.php b/src/backend/de/RaumZeitLabor/PartKeepr/REST/ApplicationController.php @@ -1,42 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\REST; - -// Class taken over from the Sencha example -class ApplicationController { - public $request, $id, $params; - - /** - * dispatch - * Dispatch request to appropriate controller-action by convention according to the HTTP method. - */ - public function dispatch($request) { - $this->request = $request; - $this->id = $request->id; - $this->params = $request->params; - - if ($request->isRestful()) { - return $this->dispatchRestful(); - } - if ($request->action) { - return $this->{$request->action}(); - } - } - - protected function dispatchRestful() { - switch ($this->request->method) { - case 'GET': - return $this->view(); - break; - case 'POST': - return $this->create(); - break; - case 'PUT': - return $this->update(); - break; - case 'DELETE': - return $this->destroy(); - break; - } - } -} - diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/REST/Model.php b/src/backend/de/RaumZeitLabor/PartKeepr/REST/Model.php @@ -1,71 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\REST; - -// Class taken over from the Sencha example -class Model { - public $id, $attributes; - static function create($params) { - $obj = new self(get_object_vars($params)); - $obj->save(); - return $obj; - } - static function find($id) { - global $dbh; - $found = null; - foreach ($dbh->rs() as $rec) { - if ($rec['id'] == $id) { - $found = new self($rec); - break; - } - } - return $found; - } - static function update($id, $params) { - global $dbh; - $rec = self::find($id); - - if ($rec == null) { - return $rec; - } - $rs = $dbh->rs(); - - foreach ($rs as $idx => $row) { - if ($row['id'] == $id) { - $rec->attributes = array_merge($rec->attributes, get_object_vars($params)); - $dbh->update($idx, $rec->attributes); - break; - } - } - return $rec; - } - static function destroy($id) { - global $dbh; - $rec = null; - $rs = $dbh->rs(); - foreach ($rs as $idx => $row) { - if ($row['id'] == $id) { - $rec = new self($dbh->destroy($idx)); - break; - } - } - return $rec; - } - static function all() { - global $dbh; - return $dbh->rs(); - } - - public function __construct($params) { - $this->id = isset($params['id']) ? $params['id'] : null; - $this->attributes = $params; - } - public function save() { - global $dbh; - $this->attributes['id'] = $dbh->pk(); - $dbh->insert($this->attributes); - } - public function to_hash() { - return $this->attributes; - } -} - diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/REST/Request.php b/src/backend/de/RaumZeitLabor/PartKeepr/REST/Request.php @@ -1,115 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\REST; - -// Class taken over from the Sencha example -class Request { - public $restful, $method, $controller, $action, $id, $params; - - public function __construct($params) { - $this->restful = (isset($params["restful"])) ? $params["restful"] : false; - $this->method = $_SERVER["REQUEST_METHOD"]; - $this->parseRequest(); - } - public function isRestful() { - return $this->restful; - } - - public function getMethod () { - return $this->method; - } - - public function getParams () { - if ($this->params === null) { - $this->params = array(); - } - - if ($this->id !== null) { - $this->params["id"] = $this->id; - } - - $this->params = array_merge($_REQUEST, $this->params); - return $this->params; - } - - public function getService () { - if ($this->controller == "") { - $this->controller = $_REQUEST["service"]; - } - - $serviceName = $this->controller."Service"; - $namespace = 'de\RaumZeitLabor\PartKeepr\\'; - $cat = $this->controller . "\\"; - $fullName= $namespace . $cat . $serviceName; - - $class = new $fullName($this->getParams()); - - return $class; - } - - public function getAction () { - return $this->action; - } - - protected function parseRequest() { - if ($this->method == 'PUT') { // <-- Have to jump through hoops to get PUT data - $raw = ''; - $httpContent = fopen('php://input', 'r'); - while ($kb = fread($httpContent, 1024)) { - $raw .= $kb; - } - fclose($httpContent); - $params = array(); - parse_str($raw, $params); - - if (isset($params['data'])) { - $this->params = json_decode($params['data'], true); - } else { - $params = json_decode($raw, true); - $this->params = $params; - } - } else { - // grab JSON data if there... - $this->params = (isset($_REQUEST['data'])) ? json_decode($_REQUEST['data'], true) : null; - - if (isset($_REQUEST['data'])) { - $this->params = json_decode($_REQUEST['data'], true); - } else { - $raw = ''; - $httpContent = fopen('php://input', 'r'); - while ($kb = fread($httpContent, 1024)) { - $raw .= $kb; - } - $params = json_decode($raw, true); - if ($params) { - $this->params = $params; - } - } - - } - // Quickndirty PATH_INFO parser - if (isset($_SERVER["PATH_INFO"])){ - $cai = '/^\/([A-Za-z]+\w)\/([A-Za-z]+\w)\/([0-9]+)$/'; // /controller/action/id - $ca = '/^\/([A-Za-z]+\w)\/([A-Za-z]+)$/'; // /controller/action - $ci = '/^\/([A-Za-z]+\w)\/([0-9]+)$/'; // /controller/id - $c = '/^\/([A-Za-z]+\w)$/'; // /controller - $i = '/^\/([0-9]+)$/'; // /id - $matches = array(); - if (preg_match($cai, $_SERVER["PATH_INFO"], $matches)) { - $this->controller = $matches[1]; - $this->action = $matches[2]; - $this->id = $matches[3]; - } else if (preg_match($ca, $_SERVER["PATH_INFO"], $matches)) { - $this->controller = $matches[1]; - $this->action = $matches[2]; - } else if (preg_match($ci, $_SERVER["PATH_INFO"], $matches)) { - $this->controller = $matches[1]; - $this->id = $matches[2]; - } else if (preg_match($c, $_SERVER["PATH_INFO"], $matches)) { - $this->controller = $matches[1]; - } else if (preg_match($i, $_SERVER["PATH_INFO"], $matches)) { - $this->id = $matches[1]; - } - } - } -} - diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/REST/Response.php b/src/backend/de/RaumZeitLabor/PartKeepr/REST/Response.php @@ -1,21 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\REST; - -// Class taken over from the Sencha example -class Response { - public $success, $data, $message, $errors, $tid, $trace; - - public function __construct($params = array()) { - $this->success = isset($params["success"]) ? $params["success"] : false; - $this->message = isset($params["message"]) ? $params["message"] : ''; - $this->data = isset($params["data"]) ? $params["data"] : array(); - } - - public function to_json() { - return json_encode(array( - 'success' => $this->success, - 'message' => $this->message, - 'data' => $this->data - )); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Service/AdminService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Service/AdminService.php @@ -1,14 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Service; - -use de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class AdminService extends Service { - public function mayCall ($call) { - if (SessionManager::getCurrentSession()->getUser()->isAdmin()) { - return true; - } else { - return false; - } - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Service/AnonService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Service/AnonService.php @@ -1,6 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Service; - -class AnonService extends Service { - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Service/Exceptions/ServiceException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Service/Exceptions/ServiceException.php @@ -1,6 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Service\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException; - -class ServiceException extends SerializableException {} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Service/RestfulService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Service/RestfulService.php @@ -1,9 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Service; - -interface RestfulService { - public function get (); - public function create (); - public function update (); - public function destroy (); -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Service/Service.php b/src/backend/de/RaumZeitLabor/PartKeepr/Service/Service.php @@ -1,110 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Service; - -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Session\Session, - de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Service\Exceptions\ServiceException; - -class Service { - private $params; - - public function __construct (Array $params) { - $this->params = $params; - } - - public function mayCall ($call) { - if (SessionManager::getCurrentSession()->getUser() === null) { - return false; - } else { - /* @todo: Implement permission checking */ - return true; - } - - - } - - protected function requireParameter ($name) { - if (!$this->hasParameter($name)) { - throw new ServiceException(sprintf("Parameter %s is required.", $name)); - } - } - - public function getParameter ($name, $default = null) { - if (!$this->hasParameter($name)) { - return $default; - } else { - return $this->params[$name]; - } - } - - /** - * Returns all parameters passed to the service - * @return array An array with all parameters (key=>value format) - */ - public function getParameters () { - return $this->params; - } - - /** - * Returns the current user for this session - * - * @return User The user - */ - public function getUser () { - return SessionManager::getCurrentSession()->getUser(); - } - - /** - * Checks if the environment has an active, logged in user. - * - * @param none - * @return boolean True if a logged in user exists, false otherwise - */ - public function hasUser () { - if (!$this->hasSession()) { - return false; - } - - var_dump($this->getUser()); - if ($this->getUser() !== null) { - return true; - } else { - return false; - } - } - - /** - * Checks if there is an active session. - * - * @param none - * @return boolean true if an active session exists, false otherwise - */ - public function hasSession () { - return SessionManager::hasSession(); - } - - public function hasParameter ($name) { - if (array_key_exists($name, $this->params)) { - return true; - } else { - return false; - } - } - - public function hasHeader ($name) { - $targetName = "HTTP_".strtoupper($name); - - return array_key_exists($targetName, $_SERVER); - } - - public function getHeader ($name) { - $targetName = "HTTP_".strtoupper($name); - - if (array_key_exists($targetName, $_SERVER)) { - return $_SERVER[$targetName]; - } else { - throw new \Exception("Header ".$targetName." not found"); - } - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Service/ServiceManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Service/ServiceManager.php @@ -1,126 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Service; - -use de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Service\Exceptions\ServiceException, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\User\UserManager, - de\RaumZeitLabor\PartKeepr\REST\Request; - -class ServiceManager { - - public static function sendHeaders () { - header("Content-Type: text/html; charset=UTF-8"); - header("Cache-Control: no-cache, must-revalidate"); - header("Access-Control-Allow-Origin: *"); - header("Access-Control-Allow-Headers: lang,call,service,X-Requested-With,X-PartKeepr-Locale,X-PartKeepr-Name,X-PartKeepr-Call"); - } - - public static function call () { - - $request = new Request(array('restful' => true)); - $service = $request->getService(); - - if ($service->hasHeader("call")) { - $call = $service->getHeader("call"); - } elseif (array_key_exists("call", $_REQUEST) && $_REQUEST["call"] != "") { - $call = $_REQUEST["call"]; - } elseif ($request->action != "") { - $call = $request->action; - } else { - switch (strtoupper($request->getMethod())) { - case "POST": - $call = "create"; - break; - case "GET": - $call = "get"; - break; - case "PUT": - $call = "update"; - break; - case "DELETE": - $call = "destroy"; - break; - default: - $call = $request->getMethod(); - break; - } - } - - $allowCall = true; - - if (!is_subclass_of($service, "de\\RaumZeitLabor\\PartKeepr\\Service\\AnonService")) { - $session = null; - $sessionid = false; - - $sessionid = self::getSession($service); - - - if ($sessionid === null) - { - $session = SessionManager::getInstance()->startSession(); - throw new ServiceException("You called a non-anonymous service, but did not pass the 'session' parameter."); - } else { - $session = SessionManager::getInstance()->resumeSession($sessionid); - } - - if (!$service->mayCall($call)) { - $allowCall = false; - } - } - - if (!$allowCall) { - throw new ServiceException("Permission denied"); - } - - if (!method_exists($service, $call)) { - throw new \Exception(sprintf("The service %s doesn't implement %s", get_class($service), $call)); - } - $result = $service->$call(); - - PartKeepr::getEM()->flush(); - - return $result; - - } - - private static function getSession ($service) { - if ($service->hasHeader("username") && $service->hasHeader("password") && !$service->hasHeader("session")) { - return self::authenticateByUsername($service->getHeader("username"), $service->getHeader("password")); - } - - if (array_key_exists("username", $_REQUEST) && array_key_exists("password", $_REQUEST) && !array_key_exists("session", $_REQUEST)) { - return self::authenticateByUsername($_REQUEST["username"], $_REQUEST["password"]); - } - - if ($service->hasHeader("session")) { - return $service->getHeader("session"); - } - - if (array_key_exists("session", $_REQUEST)) { - return $_REQUEST["session"]; - } - } - - private static function authenticateByUsername ($username, $password) { - /* Build a temporary user */ - $user = new User; - $user->setRawUsername($username); - $user->setHashedPassword($password); - - $authenticatedUser = UserManager::getInstance()->authenticate($user); - - if ($authenticatedUser !== false) { - /* Start Session */ - $session = SessionManager::getInstance()->startSession($authenticatedUser); - - return $session->getSessionID(); - } else { - throw new InvalidLoginDataException(); - } - } - -} - -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Session/Exceptions/SessionNotFoundException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Session/Exceptions/SessionNotFoundException.php @@ -1,10 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Session\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException; - -class SessionNotFoundException extends SerializableException { - public function __construct ($id) { - parent::__construct("The session with the id $id could not be found"); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Session/Session.php b/src/backend/de/RaumZeitLabor/PartKeepr/Session/Session.php @@ -1,59 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Session; - -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** @Entity */ -class Session { - - /** @Id @Column(type="integer") - * @GeneratedValue(strategy="AUTO") - */ - private $id; - - /** @Column(length=50) */ - private $sessionid; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\User\User") - */ - private $user; - - public function __construct () { - - } - - public function start () { - session_start(); - session_regenerate_id(); - session_destroy(); - unset($_SESSION); - session_start(); - - $query = PartKeepr::getEM()->createQuery("DELETE FROM de\\RaumZeitLabor\\PartKeepr\\Session\\Session s WHERE s.sessionid = :session"); - $query->setParameter("session", session_id()); - $query->execute(); - - $this->sessionid = session_id(); - } - - public function getSessionID () { - return $this->sessionid; - } - - public function resume () { - session_id($this->sessionid); - session_start(); - } - - public function getUser () { - return $this->user; - } - - public function setUser (User $user = null) { - $this->user = $user; - } - -} -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Session/SessionManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Session/SessionManager.php @@ -1,68 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Session; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Session\Exceptions\SessionNotFoundException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class SessionManager extends Singleton { - public static $currentSession = null; - - public static function getCurrentSession () { - return self::$currentSession; - } - - public static function hasSession () { - if (self::$currentSession !== null) { - return true; - } else { - return false; - } - } - - public function startSession (User $user = null) { - if (is_object($user)) { - try { - $query = PartKeepr::getEM()->createQuery("SELECT s FROM de\\RaumZeitLabor\\PartKeepr\\Session\\Session s WHERE s.user = :user"); - $query->setParameter("user", $user); - $query->execute(); - - $session = $query->getSingleResult(); - $session->resume(); - } catch (\Exception $e) { - $session = new Session; - $session->setUser($user); - $session->start(); - PartKeepr::getEM()->persist($session); - } - } else { - $session = new Session; - $session->setUser(null); - $session->start(); - PartKeepr::getEM()->persist($session); - } - - PartKeepr::getEM()->flush(); - - self::$currentSession = $session; - - return $session; - } - - public function resumeSession ($session) { - $query = PartKeepr::getEM()->createQuery("SELECT s FROM de\\RaumZeitLabor\\PartKeepr\\Session\\Session s WHERE s.sessionid = :session"); - $query->setParameter("session", $session); - $query->execute(); - try { - self::$currentSession = $query->getSingleResult(); - return self::$currentSession; - } catch (\Doctrine\ORM\NonUniqueResultException $e) { - throw new \Exception("Fatal error: Multiple sessions with id $session found."); - } catch (\Doctrine\ORM\NoResultException $e) { - throw new SessionNotFoundException($session); - } - - } -} -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/AbstractSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/AbstractSetup.php @@ -1,44 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use Doctrine\ORM\EntityManager; - -/** - * Represents a basic setup step - */ -abstract class AbstractSetup { - private $console; - - /** - * Represents the Doctrine Entity Manager - * @var Doctrine\ORM\EntityManager - */ - protected $entityManager; - - /** - * Represents all messages which are logged during setup - * @var array - */ - private $messages = array(); - - /** - * Constructs the setup step. - * @param EntityManager $em The entity manager - */ - public function __construct (EntityManager $em) { - $this->entityManager = $em; - } - - abstract public function run (); - - public function setConsole ($console) { - $this->console = $console; - } - - public function logMessage ($message) { - if ($this->console) { - echo "- ".$message."\n"; - } - $this->messages[] = $message; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/ConfigFileSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/ConfigFileSetup.php @@ -1,65 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\SerializableException; - -/** - * Creates or returns a new config file - */ -class ConfigFileSetup extends AbstractSetup { - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Setup.AbstractSetup::run() - */ - public function run () { - switch ($_REQUEST["mode"]) { - case "save": - $this->saveConfig(); - break; - case "display": - return $this->displayConfig(); - break; - } - - return null; - } - - /** - * Returns the configuration file as string, so that it can be displayed - * during setup. - * - * @param none - * @return array An array, where the "config" key contains the configuration. - */ - private function displayConfig () { - return array("config" => Configuration::dumpConfig()); - } - - /** - * Saves the configuration file. - * - * @throws SerializableException An exception which describes what has been going wrong - */ - private function saveConfig () { - $configFile = PartKeepr::getRootDirectory()."/config.php"; - - if (file_exists($configFile)) { - if (!is_writable($configFile)) { - $message = "The config.php file could not be written, because it already exists and the webserver has "; - $message .= "no write access to it."; - - throw new SerializableException($message, 10000); - } - } else { - if (!is_writable(PartKeepr::getRootDirectory())) { - $message = "The config.php file could not be written, because the webserver has no write access to it."; - - throw new SerializableException($message, 10001); - } - } - file_put_contents($configFile, Configuration::dumpConfig()); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/FootprintSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/FootprintSetup.php @@ -1,156 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\Footprint\FootprintManager, - de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategoryManager, - de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategory, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Setup\Setup; - -class FootprintSetup extends AbstractSetup { - /** - * Holds the migrated footprints - * @var array - */ - private static $migratedFootprints = array(); - - const FOOTPRINT_PATH = "../setup-data/footprints/"; - const FOOTPRINT_FILE = "../setup-data/footprints/footprints.yaml"; - - /** - * Creates the root node for the footprints - */ - public function setupRootNode () { - FootprintCategoryManager::getInstance()->ensureRootExists(); - } - - public function run () { - $this->setupRootNode(); - $this->importFootprintData(); - } - - /** - * Returns a footprint by it's partdb id - * @param int $id The footprint id from the old partdb - */ - public static function getFootprintForOldId ($id) { - return FootprintSetup::$migratedFootprints[$id]; - } - - /** - * Creates a node structure for the given path - * - * @param $path array The components of the path - * @param $node Node The parent node - */ - public function addFootprintPath (Array $path, $node) { - if (count($path) == 0) { - return $node; - } - $name = array_shift($path); - - $childNode = null; - - foreach ($node->getChildren() as $child) { - if ($child->getNode()->getName() == $name) { - $childNode = $child; - } - } - - if ($childNode === null) { - $category = new FootprintCategory(); - $category->setParent($node->getNode()->getId()); - $category->setName($name); - $childNode = FootprintCategoryManager::getInstance()->addCategory($category); - } - - return $this->addFootprintPath($path, $childNode); - } - - /** - * Checks if the specified footprint exists - * @param string $name The footprint name - */ - public function footprintExists ($name) { - $dql = "SELECT COUNT(fp) FROM de\RaumZeitLabor\PartKeepr\Footprint\Footprint fp WHERE fp.name = :name"; - $query = $this->entityManager->createQuery($dql); - $query->setParameter("name", $name); - - if ($query->getSingleScalarResult() == 0) { - return false; - } else { - return true; - } - } - - /** - * Imports the footprints - * @throws \Exception - */ - public function importFootprintData () { - $count = 0; - $skipped = 0; - - /* Import pre-defined footprints */ - $data = Setup::loadYAML(self::FOOTPRINT_FILE); - - foreach ($data as $footprintName => $footprintData) { - /* Check if the footprint with the name already exists. If yes, skip the import for the single footprint */ - if ($this->footprintExists($footprintName)) { - $skipped++; - continue; - } - $footprint = new Footprint(); - $footprint->setName($footprintName); - - if (array_key_exists("description", $footprintData)) { - $footprint->setDescription($footprintData["description"]); - } - - if (array_key_exists("category", $footprintData)) { - $footprintCategory = $this->addFootprintPath(explode("/", $footprintData["category"]), FootprintCategoryManager::getInstance()->getRootNode()); - $footprint->setCategory($footprintCategory->getNode()); - } - - if (array_key_exists("image", $footprintData)) { - $footprintImage = new FootprintImage(); - $footprintImage->setFootprint($footprint); - $footprintImage->replace(self::FOOTPRINT_PATH . $footprintData["image"]); - - $footprint->setImage($footprintImage); - } - - if (array_key_exists("attachments", $footprintData) && is_array($footprintData["attachments"])) { - foreach ($footprintData["attachments"] as $attachment) { - if (!is_array($attachment)) { - throw new \Exception("Error: The property 'attachments' of $footprintName is not an array!"); - } - if (array_key_exists("url", $attachment)) { - try { - $footprintAttachment = new FootprintAttachment(); - $footprintAttachment->setFootprint($footprint); - $footprintAttachment->replaceFromURL($attachment["url"]); - if (array_key_exists("description", $attachment)) { - $footprintAttachment->setDescription($attachment["description"]); - } - - $footprint->getAttachments()->add($footprintAttachment); - } catch (\Exception $e) { - //echo "error with url ".$attachment["url"]."\n"; - } - } - - } - } - - $this->entityManager->persist($footprint); - $count++; - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Imported %d footprints, skipped %d because they already existed", $count, $skipped)); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/ManufacturerSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/ManufacturerSetup.php @@ -1,56 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer, - de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerManager, - de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo, - de\RaumZeitLabor\PartKeepr\Setup\SiPrefixSetup; - -/** - * Sets up the manufacturers - */ -class ManufacturerSetup extends AbstractSetup { - - const MANUFACTURER_PATH = "../setup-data/manufacturers/"; - const MANUFACTURER_FILE = "../setup-data/manufacturers/manufacturers.yaml"; - - public function run () { - $this->setupManufacturers(); - } - - /** - * Sets up the manufacturers using the YAML file. - * @param $yaml string The path to the manufacturers YAML file - */ - public function setupManufacturers () { - $count=0; - $skipped=0; - $data = Setup::loadYAML(self::MANUFACTURER_FILE); - - foreach ($data as $mfgname => $logos) { - try { - ManufacturerManager::getInstance()->getManufacturerByName($mfgname); - $skipped++; - } catch (\Exception $e) { - $manufacturer = new Manufacturer(); - $manufacturer->setName($mfgname); - - $this->entityManager->persist($manufacturer); - - foreach ($logos as $logo) { - $mfglogo = new ManufacturerICLogo(); - $mfglogo->setManufacturer($manufacturer); - $mfglogo->replace(self::MANUFACTURER_PATH . "images/". $logo); - $mfglogo->setOriginalFilename($logo); - - $this->entityManager->persist($mfglogo); - } - $count++; - } - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Imported %d Manufacturers, skipped %d because they already exist", $count, $skipped)); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/DistributorMigration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/DistributorMigration.php @@ -1,34 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Distributor\Distributor, - de\RaumZeitLabor\PartKeepr\Distributor\DistributorManager, - de\RaumZeitLabor\PartKeepr\Setup\AbstractSetup; - -class DistributorMigration extends AbstractSetup { - /** - * Migrates the existing distributors - */ - public function run () { - $count = 0; - $skipped = 0; - $r = mysql_query("SELECT * FROM suppliers"); - while ($supplier = mysql_fetch_assoc($r)) { - $name = PartDBMigration::convertText($supplier["name"]); - try { - $distributor = DistributorManager::getInstance()->getDistributorByName($name); - $skipped++; - } catch (\Exception $e) { - $distributor = new Distributor(); - $distributor->setName($name); - - $this->entityManager->persist($distributor); - $count++; - } - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Migrated %d distributors, skipped %d because they already exist", $count, $skipped)); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/FootprintMigration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/FootprintMigration.php @@ -1,43 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Footprint\Footprint, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintManager, - de\RaumZeitLabor\PartKeepr\FootprintCategory\FootprintCategoryManager, - de\RaumZeitLabor\PartKeepr\Setup\FootprintSetup; - -class FootprintMigration extends FootprintSetup { - /** - * Migrates the existing footprints - */ - public function run () { - $count = 0; - $skipped = 0; - - // Get or create node for the imported footprints - $footprintCategory = FootprintSetup::addFootprintPath(explode("/", "Imported Footprints"), FootprintCategoryManager::getInstance()->getRootNode()); - - $r = mysql_query("SELECT * FROM footprints"); - - while ($sFootprint = mysql_fetch_assoc($r)) { - $name = PartDBMigration::convertText($sFootprint["name"]); - - try { - FootprintManager::getInstance()->getFootprintByName($name); - $skipped++; - } catch (\Exception $e) { - $footprint = new Footprint(); - $footprint->setName($name); - - $footprint->setCategory($footprintCategory->getNode()); - - $this->entityManager->persist($footprint); - $count++; - } - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Migrated %d footprints, skipped %d because they already exist", $count, $skipped)); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartCategoryMigration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartCategoryMigration.php @@ -1,50 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Setup\AbstractSetup; - -class PartCategoryMigration extends AbstractSetup { - private $categories = array(); - private static $migratedCategories = array(); - /** - * Migrates the old categories - */ - public function run () { - $this->addCategoryRecursive(0, array()); - - foreach ($this->categories as $oldid => $category) { - $newcategory = PartCategoryManager::getInstance()->createCategoryTreeByArray($category); - - self::$migratedCategories[$oldid] = $newcategory; - } - - } - - /** - * Creates the category tree, recursive - * @param array $aCategories the categories - * @param id $currentId The current ID to migrate - * @param Node $parent The parent node - */ - private function addCategoryRecursive ($parentId, $parents) { - $r = mysql_query("SELECT * FROM categories WHERE parentnode = ".intval($parentId)); - - while ($category = mysql_fetch_array($r)) { - $aCopy = $parents; - $aCopy[] = $category["name"]; - - $this->categories[$category["id"]] = $aCopy; - $this->addCategoryRecursive($category["id"], $aCopy); - } - } - - public static function getMigratedCategory ($id) { - if (!array_key_exists($id, self::$migratedCategories)) { - print_r(self::$migratedCategories); - } - return self::$migratedCategories[$id]; - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartDBMigration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartDBMigration.php @@ -1,71 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Configuration as PartKeeprConfiguration; - -class PartDBMigration { - /** - * Specifies if setup runs in console mode. - * @var boolean - */ - private $console = false; - - /** - * Runs the setup with all steps - */ - public function run () { - $this->runStep("all"); - } - - /** - * Sets console mode. - * - * In this mode, messages are directly written to the console. - */ - public function setConsole () { - $this->console = true; - } - - /** - * Runs a specific setup step, or all steps. - * @param string $step - * @throws \Exception - */ - public function runStep ($step) { - $entityManager = PartKeepr::getEM(); - - $aSteps = array( - "distributor" => new DistributorMigration($entityManager), - "footprint" => new FootprintMigration($entityManager), - "partcategory" => new PartCategoryMigration($entityManager), - "storagelocation" => new StorageLocationMigration($entityManager), - "part" => new PartMigration($entityManager) - ); - - if ($step == "all") { - foreach ($aSteps as $step) { - $step->setConsole($this->console); - $step->run(); - } - } else { - if (array_key_exists($step, $aSteps)) { - $aSteps[$step]->run(); - } else { - throw new \Exception(sprintf("Migration step %s doesn't exist", $step)); - } - } - } - - /** - * Converts strange escpaes in the database to "regular" text. - * @param string $string The string to convert - * @return string The converted string - */ - public static function convertText ($string) { - $string = stripslashes($string); - $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8'); - $string = str_replace("&#937;", "Ω", $string); - return $string; - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartMigration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/PartMigration.php @@ -1,131 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\Part, - de\RaumZeitLabor\PartKeepr\Part\PartAttachment, - de\RaumZeitLabor\PartKeepr\Part\PartDistributor, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\Distributor\DistributorManager, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintManager, - de\RaumZeitLabor\PartKeepr\PartUnit\PartUnitManager, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationManager, - de\RaumZeitLabor\PartKeepr\Setup\AbstractSetup; - -class PartMigration extends AbstractSetup { - /** - * Migrates the existing distributors - */ - public function run () { - $count = 0; - $skipped = 0; - $fc = 0; - - $r = mysql_query("SELECT * FROM parts"); - - while ($part = mysql_fetch_assoc($r)) { - $name = PartDBMigration::convertText($part["name"]); - - $oPart = new Part(); - $oPart->setName($name); - $oPart->setComment(PartDBMigration::convertText($part["comment"])); - - $oPart->setFootprint($this->getFootprintForPart($part["id"])); - $oPart->setReviewFlag(true); - $category = PartCategoryMigration::getMigratedCategory($part["id_category"]); - - if ($category === null) { - PartCategoryManager::getInstance()->getRootNode()->getNode(); - } else { - $oPart->setCategory($category); - } - - $oPart->setStorageLocation($this->getStorageLocationForPart($part["id"])); - $oPart->setMinStockLevel($part["mininstock"]); - $oPart->setPartUnit(PartUnitManager::getInstance()->getDefaultPartUnit()); - - $partDistributor = new PartDistributor(); - $partDistributor->setPart($oPart); - $partDistributor->setDistributor($this->getDistributorForPart($part["id"])); - $partDistributor->setOrderNumber($part["supplierpartnr"]); - $oPart->getDistributors()->add($partDistributor); - - - /* Add existing datasheets */ - $datasheetQuery = "SELECT datasheeturl FROM datasheets WHERE part_id = ".$part["id"]; - $r3 = mysql_query($datasheetQuery); - while ($res = mysql_fetch_assoc($r3)) { - try { - $attachment = new PartAttachment(); - $attachment->setPart($oPart); - $attachment->replaceFromURL($res["datasheeturl"]); - $attachment->setDescription(PartKeepr::i18n("Datasheet")); - $oPart->getAttachments()->add($attachment); - } catch (\Exception $e) { - Setup::progress(" - error with url ".$res["datasheeturl"].". Maybe the datasheet was not found."); - Setup::progress(" - The exception error was: ".$e->getMessage()); - } - } - - PartKeepr::getEM()->persist($oPart); - - $oStock = new StockEntry($oPart, $part["instock"]); - - $priceQuery = "SELECT AVG(preis) AS preis FROM preise WHERE part_id = ".$part["id"]; - - $r2 = mysql_query($priceQuery); - $res = mysql_fetch_assoc($r2); - - if ($res) { - if ($res["preis"] !== null) { - $oStock->setPrice(floatval($res["preis"])); - } - } - - PartKeepr::getEM()->persist($oStock); - - $fc++; - - // Flush every STEP_SIZE parts - if ($fc>PartMigration::STEP_SIZE) { - PartKeepr::getEM()->flush(); - $fc=0; - } - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Migrated %d parts, skipped %d because they already exist", $count, $skipped)); - } - - private function getFootprintForPart ($oldid) { - $r = mysql_query("SELECT footprints.name FROM footprints, parts WHERE footprints.id = parts.id_footprint AND parts.id = ".intval($oldid)); - - $data = mysql_fetch_assoc($r); - - return FootprintManager::getInstance()->getFootprintByName(PartDBMigration::convertText($data["name"])); - } - - private function getStorageLocationForPart ($oldid) { - $r = mysql_query("SELECT storeloc.name FROM storeloc, parts WHERE storeloc.id = parts.id_storeloc AND parts.id = ".intval($oldid)); - - $data = mysql_fetch_assoc($r); - - return StorageLocationManager::getInstance()->getStorageLocationByName(PartDBMigration::convertText($data["name"])); - } - - private function getDistributorForPart ($oldid) { - $r = mysql_query("SELECT suppliers.name FROM suppliers, parts WHERE suppliers.id = parts.id_supplier AND parts.id = ".intval($oldid)); - - $data = mysql_fetch_assoc($r); - - return DistributorManager::getInstance()->getDistributorByName(PartDBMigration::convertText($data["name"])); - } - - /** - * Defines the size of the records which are held in memory unless we flush to the DB. - * @var int - */ - const STEP_SIZE = 100; -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/StorageLocationMigration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Migration/PartDB/StorageLocationMigration.php @@ -1,51 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationManager, - de\RaumZeitLabor\PartKeepr\Setup\AbstractSetup; - -class StorageLocationMigration extends AbstractSetup { - /** - * Holds the migrated storage locations - * @var array - */ - private static $migratedStorageLocations = array(); - - /** - * Migrates the storage locations - */ - public function run () { - $count = 0; - $skipped = 0; - - $r = mysql_query("SELECT * FROM storeloc"); - - while ($store = mysql_fetch_assoc($r)) { - $name = PartDBMigration::convertText($store["name"]); - try { - $storageLocation = StorageLocationManager::getInstance()->getStorageLocationByName($name); - $skipped++; - } catch (\Exception $e) { - $oStorageLocation = new StorageLocation(); - $oStorageLocation->setName($name); - - $this->entityManager->persist($oStorageLocation); - $count++; - } - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Migrated %d storage locations, skipped %d because they already exist", $count, $skipped)); - - } - - /** - * Returns the storage location by id - * @param int $id - */ - public static function getMigratedStorageLocation ($id) { - return StorageLocationSetup::$migratedStorageLocations[$id]; - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/MiscSettingsSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/MiscSettingsSetup.php @@ -1,69 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\CronLogger\CronLoggerManager, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Sets up misc stuff, which doesn't fit into other steps - */ -class MiscSettingsSetup extends AbstractSetup { - public function run () { - $this->markCronjobsAsRun(); - $this->clearAPCCache(); - $this->regenerateProxies(); - } - - /** - * Marks the cronjobs as run, so that the user doesn't get an error during the first day. - * - * This is necessary because if the user sets up the system and enters the cronjobs, there is a chance - * that no cronjob has been ran when he logs in the first time and thus gets confused. - */ - public function markCronjobsAsRun () { - foreach (PartKeepr::getRequiredCronjobs() as $cronjob) { - CronLoggerManager::getInstance()->markCronRun($cronjob); - } - } - - /** - * Clears the APC cache to push out old entries - */ - public function clearAPCCache () { - if (function_exists("apc_clear_cache")) { - apc_clear_cache(); - apc_clear_cache("user"); - } - } - - /** - * Re-generates all proxies. This is analog to doctrine orm:generate-proxies - * - * @throws \InvalidArgumentException - */ - public function regenerateProxies () { - $em = $this->entityManager; - - $metadatas = $em->getMetadataFactory()->getAllMetadata(); - $destPath = $em->getConfiguration()->getProxyDir(); - - if ( ! is_dir($destPath)) { - mkdir($destPath, 0777, true); - } - - $destPath = realpath($destPath); - - if ( ! file_exists($destPath)) { - throw new \InvalidArgumentException( - sprintf("Proxies destination directory '<info>%s</info>' does not exist.", $em->getConfiguration()->getProxyDir()) - ); - } else if ( ! is_writable($destPath)) { - throw new \InvalidArgumentException( - sprintf("Proxies destination directory '<info>%s</info>' does not have write permissions.", $destPath) - ); - } - - $em->getProxyFactory()->generateProxyClasses($metadatas, $destPath); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/PartCategorySetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/PartCategorySetup.php @@ -1,28 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategory; - -class PartCategorySetup extends AbstractSetup { - /** - * Sets up the root category node - */ - public function setupRootCategory () { - PartCategoryManager::getInstance()->ensureRootExists(); - } - - public function updateCategoryPathCache () { - PartCategoryManager::getInstance()->updateCategoryPaths( - PartCategoryManager::getInstance()->getRootNode() - ); - - PartKeepr::getEM()->flush(); - } - - public function run () { - $this->setupRootCategory(); - $this->updateCategoryPathCache(); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/PartUnitSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/PartUnitSetup.php @@ -1,36 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\PartUnit; - -class PartUnitSetup extends AbstractSetup { - /** - * Holds the default unit - * @var object - */ - private static $defaultUnit; - - /** - * Sets up the default part unit if none exists - */ - public function run () { - $dql = "SELECT COUNT(p) FROM de\RaumZeitLabor\PartKeepr\Part\PartUnit p WHERE p.is_default = :default"; - $query = $this->entityManager->createQuery($dql); - $query->setParameter("default", true); - - if ($query->getSingleScalarResult() == 0) { - $partUnit = new PartUnit(); - $partUnit->setName(PartKeepr::i18n("Pieces")); - $partUnit->setShortName(PartKeepr::i18n("pcs")); - $partUnit->setDefault(true); - - $this->entityManager->persist($partUnit); - $this->entityManager->flush(); - - $this->logMessage("Added default part unit"); - } else { - $this->logMessage("Skipped adding default part unit, because a default part unit already exists"); - } - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/SchemaSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/SchemaSetup.php @@ -1,34 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; -/** - * Updates (or creates) the database schema - */ -class SchemaSetup extends AbstractSetup { - public function run () { - $tool = new \Doctrine\ORM\Tools\SchemaTool($this->entityManager); - $classes = PartKeepr::getClassMetaData(); - $tool->updateSchema($classes, true); - $this->logMessage("Database Schema created/updated"); - } - - /** - * Checks if the specified database has UTF-8 encoding - * @param $connection The DBAL connection - * @param string $dbname - */ - public static function mysqlHasUTF8Encoding ($connection, $dbname) { - $statement = $connection->prepare("SELECT default_character_set_name FROM information_schema.SCHEMATA S WHERE schema_name = :schema"); - $statement->bindValue("schema", $dbname); - $statement->execute(); - - $encoding = $statement->fetchColumn(0); - - if ($encoding != "utf8") { - return false; - } else { - return true; - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Setup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/Setup.php @@ -1,176 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Configuration as PartKeeprConfiguration; - -class Setup { - /** - * Specifies if setup runs in console mode. - * @var boolean - */ - private $console = false; - - /** - * Defines if the setup runs in verbose mode. - * @var boolean - */ - private static $verbose = false; - - /** - * Runs the migration with all steps - */ - public function run () { - $this->runStep("all"); - } - - /** - * Sets console mode. - * - * In this mode, messages are directly written to the console. - */ - public function setConsole () { - $this->console = true; - } - - /** - * Runs a specific setup step, or all steps. - * - * @param string $step The step to execute - * @throws \Exception - */ - public function runStep ($step) { - $entityManager = PartKeepr::getEM(); - - $aSteps = array( - "schema" => new SchemaSetup($entityManager), - "adminuser" => new UserSetup($entityManager), - "partunit" => new PartUnitSetup($entityManager), - "footprint" => new FootprintSetup($entityManager), - "partcategory" => new PartCategorySetup($entityManager), - "siprefix" => new SiPrefixSetup($entityManager), - "unit" => new UnitSetup($entityManager), - "manufacturer" => new ManufacturerSetup($entityManager), - "miscsettings" => new MiscSettingsSetup($entityManager) - ); - - $aActions = array( - "configfile" => new ConfigFileSetup($entityManager) - ); - if ($step == "all") { - foreach ($aSteps as $step) { - $step->setConsole($this->console); - $step->run(); - } - } else { - if (array_key_exists($step, $aSteps)) { - return $aSteps[$step]->run(); - } - - if (array_key_exists($step, $aActions)) { - return $aActions[$step]->run(); - } - - throw new \Exception(sprintf("Setup step %s doesn't exist", $step)); - } - } - - /** - * Tests for APC. Throws an exception if APC is missing or not active. - * @throws \Exception - */ - public function testAPC () { - if (!extension_loaded("apc")) { - throw new \Exception(PartKeepr::i18n("The extension 'apc' is not loaded. Make sure that it is installed (see http://php.net/manual/en/apc.installation.php) and that it is enabled (set apc.enabled=1 in your php.ini).")); - } - } - - /** - * Tests for suitable memory_limit settings - * @todo stub - */ - public function testMemoryLimit () { - //echo ini_get("memory_limit"); - } - - /** - * Sets the verbose flag - * @param boolean $verbose True if verbose output is wanted, false otherwise - */ - public static function setVerbose ($verbose) { - Setup::$verbose = $verbose; - } - - /** - * Outputs a progress message. - * - * @param string $string The string to output - * @param boolean $verbose True if the string should only be printed if verbosity is turned on - */ - public static function progress ($string, $verbose = false) { - if (!$verbose || ($verbose && Setup::$verbose)) { - echo $string."\n"; - } - - } - - /** - * Loads the given YAML file. Due to an API brach between Doctrine 2.0.5 and Doctrine 2.0.6, - * we need to work it around. - * @param string $file The path of the file to load - * @return array The parsed YAML file - */ - public static function loadYAML ($file) { - return \Symfony\Component\Yaml\Yaml::parse($file); - } - - /** - * Sets the database configuration array from $_REQUEST - */ - public static function setDatabaseConfigurationFromRequest () { - if (isset($_REQUEST["dbname"])) { - PartKeeprConfiguration::setOption("partkeepr.database.dbname", $_REQUEST["dbname"]); - } - - if (isset($_REQUEST["user"])) { - PartKeeprConfiguration::setOption("partkeepr.database.username", $_REQUEST["user"]); - } - if (isset($_REQUEST["password"])) { - PartKeeprConfiguration::setOption("partkeepr.database.password", $_REQUEST["password"]); - } - if (isset($_REQUEST["host"])) { - PartKeeprConfiguration::setOption("partkeepr.database.host", $_REQUEST["host"]); - } - - if (isset($_REQUEST['port'])) { - PartKeeprConfiguration::setOption("partkeepr.database.port", $_REQUEST["port"]); - } - - switch ($_REQUEST["driver"]) { - case "mysql": - PartKeeprConfiguration::setOption("partkeepr.database.driver","pdo_mysql"); - break; - case "pgsql": - PartKeeprConfiguration::setOption("partkeepr.database.driver","pdo_pgsql"); - break; - default: - throw new \Exception(sprintf("Invalid driver %s specified.", $_REQUEST["driver"])); - break; - } - } - - /** - * Runs some checks for the CLI setup - */ - public function runCLIChecks () { - - if (PartKeeprConfiguration::getOption("partkeepr.database.driver") == "pdo_mysql") { - $dbname = PartKeeprConfiguration::getOption("partkeepr.database.dbname"); - if (!SchemaSetup::mysqlHasUTF8Encoding(PartKeepr::getEM()->getConnection(), $dbname )) { - echo "Error: The database $dbname hasn't got the UTF-8 encoding. You need to set the database encoding to UTF-8. Aborting.\n"; - die; - } - } - - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/SiPrefixSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/SiPrefixSetup.php @@ -1,47 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix, - de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefixManager; - -class SiPrefixSetup extends AbstractSetup { - - const SIPREFIX_DATA_FILE = "../setup-data/siprefixes.yaml"; - - /** - * Stores the migrated si prefixes - * @var array - */ - private static $siPrefixes = array(); - - public function run () { - $this->setupSiPrefixes(); - } - - /** - * Sets up the SI prefixes - */ - public function setupSiPrefixes () { - $count = 0; - $skipped = 0; - - $data = Setup::loadYAML(self::SIPREFIX_DATA_FILE); - - foreach ($data as $prefixName => $data) { - if (!SiPrefixManager::getInstance()->siPrefixExists($prefixName)) { - $prefix = new SiPrefix(); - $prefix->setPrefix($prefixName); - $prefix->setPower($data["power"]); - $prefix->setSymbol($data["symbol"]); - $this->entityManager->persist($prefix); - $count++; - } else { - $skipped++; - } - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Imported %d Si Prefixes, skipped %d", $count, $skipped)); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/UnitSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/UnitSetup.php @@ -1,62 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Unit\Unit, - de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefixManager, - de\RaumZeitLabor\PartKeepr\Unit\UnitManager, - de\RaumZeitLabor\PartKeepr\Setup\SiPrefixSetup; - -class UnitSetup extends AbstractSetup { - - const UNIT_DATA_FILE = "../setup-data/units.yaml"; - - - public function run () { - $this->setupUnits(); - } - /** - * Sets up the default units - * @throws \Exception - */ - public function setupUnits () { - $count = 0; - $skipped = 0; - $data = Setup::loadYAML(self::UNIT_DATA_FILE); - - $aUnits = array(); - - foreach ($data as $unitName => $data) { - if (UnitManager::getInstance()->unitExists($unitName)) { - $skipped++; - continue; - } - $unit = new Unit(); - $unit->setName($unitName); - $unit->setSymbol($data["symbol"]); - - if (array_key_exists("prefixes", $data)) { - if (!is_array($data["prefixes"])) { - throw new \Exception($unitName." doesn't contain a prefix list, or the prefix list is not an array."); - } - - foreach ($data["prefixes"] as $prefix) { - - $siPrefix = SiPrefixManager::getInstance()->getSiPrefixBySymbol($prefix); - if ($siPrefix === false) { - throw new \Exception("Unable to find prefix ".$prefix); - } - $unit->getPrefixes()->add($siPrefix); - } - } - - PartKeepr::getEM()->persist($unit); - $count++; - } - - $this->entityManager->flush(); - $this->logMessage(sprintf("Imported %d Units, skipped %d because they already exist", $count, $skipped)); - } - - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Setup/UserSetup.php b/src/backend/de/RaumZeitLabor/PartKeepr/Setup/UserSetup.php @@ -1,31 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Setup; - -use de\RaumZeitLabor\PartKeepr\User\User; - -/** - * Creates a new admin user, but only if no admin user exists. - */ -class UserSetup extends AbstractSetup { - public function run () { - $dql = "SELECT COUNT(u) FROM de\RaumZeitLabor\PartKeepr\User\User u WHERE u.username = :username OR u.admin = :admin"; - $query = $this->entityManager->createQuery($dql); - $query->setParameter("username", "admin"); - $query->setParameter("admin", true); - - if ($query->getSingleScalarResult() == 0) { - $user = new User(); - $user->setUsername("admin"); - $user->setPassword("admin"); - $user->setAdmin(true); - - $this->entityManager->persist($user); - $this->entityManager->flush(); - - $this->logMessage("Admin User created"); - } else { - $this->logMessage( "Skipped admin user creation, because an user named 'admin'". - "or another user with an admin flag already exists"); - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefix.php b/src/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefix.php @@ -1,91 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\SiPrefix; - -use de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Exceptions\OutOfRangeException; - - -/** @Entity **/ -class SiPrefix extends BaseEntity { - /** - * The prefix of the Si-Prefix (e.g. yotta, deca, deci, centi) - * @Column(type="string") - * @var string - */ - private $prefix; - - /** - * The symbol of the Si-Prefix (e.g. m, M, G) - * @Column(type="string",length=2) - * @var string - */ - private $symbol; - - /** - * The power of the Si-Prefix (e.g. milli = 10^-3) - * @Column(type="integer") - * @var int - */ - private $power; - - /** - * Sets the prefix name. - * @param string $prefix - */ - public function setPrefix ($prefix) { - $this->prefix = $prefix; - } - - /** - * Returns the prefix name - * @return string The prefix name - */ - public function getPrefix () { - return $this->prefix; - } - - /** - * Sets the symbol for the prefix - * @param string $symbol The symbol - */ - public function setSymbol ($symbol) { - $this->symbol = $symbol; - } - - /** - * Returns the symbol for the prefix - * @return string The symbol - */ - public function getSymbol () { - return $this->symbol; - } - - /** - * Sets the power in a 10^n power (n=power) - * @param int $power The 10^power - */ - public function setPower ($power) { - $this->power = $power; - } - - /** - * Returns the power (10^n) - * @return int The power - */ - public function getPower () { - return $this->power; - } - - /** - * Serializes the object into an array format. - * @return array the object in serialized format. - */ - public function serialize () { - return array( - "id" => $this->getId(), - "symbol" => $this->getSymbol(), - "prefix" => $this->getPrefix(), - "power" => $this->getPower()); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefixManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefixManager.php @@ -1,42 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\SiPrefix; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class SiPrefixManager extends Singleton { - public $siPrefixSymbolCache = array(); - - public function getSiPrefixBySymbol ($symbol) { - if (!is_array($this->siPrefixSymbolCache) || count($this->siPrefixSymbolCache) == 0) { - $this->createSiPrefixSymbolCache(); - } - - foreach ($this->siPrefixSymbolCache as $entry) { - if ($entry->getSymbol() == $symbol) { - return $entry; - } - } - - throw new \Exception(sprintf("Symbol '%s' not found", $symbol)); - } - - private function createSiPrefixSymbolCache () { - $dql = "SELECT sip FROM de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix sip"; - $query = PartKeepr::getEM()->createQuery($dql); - - $this->siPrefixSymbolCache = $query->getResult(); - } - - public function siPrefixExists ($prefix) { - $dql = "SELECT COUNT(sip) FROM de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix sip WHERE sip.prefix = :prefix"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("prefix", $prefix); - - if ($query->getSingleScalarResult() == 0) { - return false; - } else { - return true; - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefixService.php b/src/backend/de/RaumZeitLabor/PartKeepr/SiPrefix/SiPrefixService.php @@ -1,27 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\SiPrefix; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class SiPrefixService extends Service implements RestfulService { - public function get () { - $query = PartKeepr::getEM()->createQuery("SELECT si.id, si.prefix, si.symbol, si.power FROM de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix si"); - - return array("data" => $query->getArrayResult()); - } - - public function create () { - throw new \Exception("Not yet implemented"); - } - - public function update () { - throw new \Exception("Not yet implemented"); - } - - public function destroy () { - throw new \Exception("Not yet implemented"); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticService.php @@ -1,148 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Statistic; - -use de\RaumZeitLabor\PartKeepr\Part\PartUnit, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\PartUnit\PartUnitManager; - -class StatisticService extends Service { - public function getCurrentStats () { - - $aData = array(); - $aData["partCount"] = PartManager::getInstance()->getPartCount(); - $aData["categoryCount"] = PartCategoryManager::getInstance()->getCategoryCount(); - $aData["totalPrice"] = PartManager::getInstance()->getTotalPrice(); - $aData["averagePrice"] = PartManager::getInstance()->getAveragePrice(); - $aData["partsWithPrice"] = PartManager::getInstance()->getPartCount(true); - $aData["partsWithoutPrice"] = $aData["partCount"] - $aData["partsWithPrice"]; - - $result = PartUnitManager::getInstance()->getUnitCounts(); - - $aUnits = array(); - - foreach ($result as $row) { - $aUnits[] = array( - "name" => PartUnit::loadById($row["puid"])->getName(), - "stockLevel" => $row["stockLevel"]); - } - - $aData["units"] = $aUnits; - - return $aData; - } - - /** - * Returns the range of all recorded statistic snapshots. - */ - public function getStatisticRange () { - $dql = "SELECT MIN(sts.dateTime), MAX(sts.dateTime) FROM de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshot sts"; - $query = PartKeepr::getEM()->createQuery($dql); - - $data = $query->getArrayResult(); - - return array("data" => array("start" => $data[0][1], "end" => $data[0][2])); - - } - /** - * Returns sampled statistics from the database. - * - * This call takes a start and an end time, and calculates a set of statistics - * for each interval. - * - * The sampleSize, which has a default of 50, specifies how many single statistic - * points in the given date interval will be returned. - * - * This function interpolates the statistics if there are not enough statistic samples available. - */ - public function getSampledStatistics () { - $fooStart = microtime(true); - - $this->requireParameter("startDateTime"); - $this->requireParameter("endDateTime"); - - - $start = \DateTime::createFromFormat("Y-m-d H:i:s", $this->getParameter("startDateTime")); - $end = \DateTime::createFromFormat("Y-m-d H:i:s", $this->getParameter("endDateTime")); - - if ($start->getTimestamp() > $end->getTimestamp()) { - // Swap both times - list($start, $end) = array($end, $start); - } - - if ($this->hasParameter("sampleSize")) { - $sampleSize = $this->getParameter("sampleSize"); - } else { - $sampleSize = 25; - } - - $intervalSize = intval(($end->getTimestamp() - $start->getTimestamp()) / $sampleSize); - - $queryStartTime = clone $start; - $queryEndTime = clone $start; - $queryEndTime->add(new \DateInterval("PT".$intervalSize."S")); - - $partUnitQuery = "SELECT pu FROM de\RaumZeitLabor\PartKeepr\Part\PartUnit pu"; - $query = PartKeepr::getEM()->createQuery($partUnitQuery); - - $aPartUnits = $query->getResult(); - - $aRecords = array(); - - $dql = "SELECT AVG(sts.parts) AS parts, AVG(sts.categories) AS categories FROM de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshot sts WHERE sts.dateTime >= :start AND sts.dateTime <= :end"; - $mainQuery = PartKeepr::getEM()->createQuery($dql); - - $dql = "SELECT AVG(stsu.stockLevel) AS stockLevel FROM de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshotUnit stsu JOIN stsu.statisticSnapshot sts WHERE sts.dateTime >= :start AND sts.dateTime <= :end AND stsu.partUnit = :partUnit"; - $subQuery = PartKeepr::getEM()->createQuery($dql); - - for ($i=0;$i<$sampleSize;$i++) { - - - $mainQuery->setParameter("start", $queryStartTime); - $mainQuery->setParameter("end", $queryEndTime); - - $result = $mainQuery->getResult(); - - $record = $result[0]; - - if ($record["parts"] !== null) { - $record["parts"] = floatval($record["parts"]); - } - - if ($record["categories"] !== null) { - $record["categories"] = floatval($record["categories"]); - } - - foreach ($aPartUnits as $partUnit) { - $subQuery->setParameter("start", $queryStartTime); - $subQuery->setParameter("end", $queryEndTime); - $subQuery->setParameter("partUnit", $partUnit); - - $aResult = $subQuery->getResult(); - - if ($aResult[0]["stockLevel"] !== null) { - $record["units"][$partUnit->getName()] = floatval($aResult[0]["stockLevel"]); - } else { - $record["units"][$partUnit->getName()] = null; - } - - } - - $record["start"] = $queryStartTime->format("Y-m-d H:i:s"); - - if ($record["parts"] !== null) { - $aRecords[] = $record; - } - - - $queryStartTime->add(new \DateInterval("PT".$intervalSize."S")); - $queryEndTime->add(new \DateInterval("PT".$intervalSize."S")); - } - - - return array("status" => "ok", "data" => $aRecords); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshot.php b/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshot.php @@ -1,109 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Statistic; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** @Entity **/ -class StatisticSnapshot { - /** - * @Id @Column(type="integer") - * @GeneratedValue(strategy="AUTO") - * @var integer - */ - private $id; - - /** - * Defines the date when this snapshot has been taken - * @Column(type="datetime") - * @var DateTime - */ - private $dateTime; - - /** - * Defines the amount of different parts in the database - * @Column(type="integer") - * @var int - */ - private $parts; - - /** - * Defines the amount of categories - * @Column(type="integer") - * @var int - */ - private $categories; - - /** - * Holds all defined units in the database - * @OneToMany(targetEntity="de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshotUnit",mappedBy="statisticSnapshot",cascade={"persist", "remove"}) - */ - private $units; - - /** - * Creates a new statistic snapshot - */ - public function __construct () { - $this->units = new \Doctrine\Common\Collections\ArrayCollection(); - $this->setDateTime(new \DateTime()); - } - - /** - * Sets the date+time for the snapshot - * @param \DateTime $dateTime The date+time for the snapshot - */ - public function setDateTime (\DateTime $dateTime) { - $this->dateTime = $dateTime; - } - - /** - * Returns the date+time for the snapshot - * @return DateTime The date+time for the snapshot - */ - public function getDateTime () { - return $this->dateTime; - } - - /** - * Sets the amount of overall parts for the snapshot - * @param int $parts The amount of parts - */ - public function setParts ($parts) { - $this->parts = $parts; - } - - /** - * Returns the amount of overall parts for the snapshot - * @return int The amount of parts - */ - public function getParts () { - return $this->parts; - } - - /** - * Sets the amount of categories for the snapshot - * @param int $categories The amount of categories - */ - public function setCategories ($categories) { - $this->categories = $categories; - } - - /** - * Returns the amount of categories - * @return int The amount of categories - */ - public function getCategories () { - return $this->categories; - } - - /** - * Returns the ID of this snapshot - * @return int The ID of this snapshot - */ - public function getId () { - return $this->id; - } - - public function getUnits () { - return $this->units; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshotManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshotManager.php @@ -1,38 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Statistic; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\Part\PartUnit, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\PartUnit\PartUnitManager, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\PartUnit\Exceptions\PartUnitNotFoundException; - -class StatisticSnapshotManager extends Singleton { - public function createSnapshot () { - - $snapshot = new StatisticSnapshot(); - $snapshot->setParts(PartManager::getInstance()->getPartCount()); - $snapshot->setCategories(PartCategoryManager::getInstance()->getCategoryCount()); - - $result = PartUnitManager::getInstance()->getUnitCounts(); - - foreach ($result as $row) { - $snapshotUnit = new StatisticSnapshotUnit(); - $snapshotUnit->setPartUnit(PartUnit::loadById($row["puid"])); - $snapshotUnit->setStatisticSnapshot($snapshot); - - if ($row["stockLevel"] !== null) { - $snapshotUnit->setStockLevel($row["stockLevel"]); - } else { - $snapshotUnit->setStockLevel(0); - } - - $snapshot->getUnits()->add($snapshotUnit); - } - - PartKeepr::getEM()->persist($snapshot); - PartKeepr::getEM()->flush(); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshotUnit.php b/src/backend/de/RaumZeitLabor/PartKeepr/Statistic/StatisticSnapshotUnit.php @@ -1,95 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Statistic; - -use de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshot, - de\RaumZeitLabor\PartKeepr\Part\PartUnit, - de\RaumZeitLabor\PartKeepr\PartKeepr; - - -/** @Entity **/ -class StatisticSnapshotUnit { - /** - * @Id @Column(type="integer") - * @GeneratedValue(strategy="AUTO") - * @var integer - */ - private $id; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Statistic\StatisticSnapshot") - * The statistic snapshot this entity belongs to - * @var StatisticSnapshot - */ - private $statisticSnapshot; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\PartUnit") - * The statistic snapshot this entity belongs to - * @var StatisticSnapshot - */ - private $partUnit; - - /** - * The stockLevel for the unit - * @Column(type="integer") - * @var int - */ - private $stockLevel; - - /** - * Sets the statistic snapshot this entity belongs to - * @param StatisticSnapshot $snapshot The snapshot - */ - public function setStatisticSnapshot (StatisticSnapshot $snapshot) { - $this->statisticSnapshot = $snapshot; - } - - /** - * Returns the snapshot this entity belongs to - * @return StatisticSnapshot The snapshot - */ - public function getStatisticSnapshot () { - return $this->statisticSnapshot; - } - - /** - * - * Sets the part unit for this entity - * @param PartUnit $unit The part unit - */ - public function setPartUnit (PartUnit $unit) { - $this->partUnit = $unit; - } - - /** - * Returns the part unit for this entity - * @return PartUnit The part unit - */ - public function getPartUnit () { - return $this->partUnit; - } - - /** - * Returns the ID of this statistic snapshot unit - * @return int The ID - */ - public function getId () { - return $this->id; - } - - /** - * Sets the stock level for this unit snapshot - * @param int $stockLevel - */ - public function setStockLevel ($stockLevel) { - $this->stockLevel = $stockLevel; - } - - /** - * Returns the stock level for this unit snapshot - * @return int The stock level - */ - public function getStockLevel () { - return $this->stockLevel; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Stock/StockEntry.php b/src/backend/de/RaumZeitLabor/PartKeepr/Stock/StockEntry.php @@ -1,239 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Stock; - -use de\RaumZeitLabor\PartKeepr\Part\Part, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\Util\Serializable; - -/** @Entity @HasLifecycleCallbacks **/ -class StockEntry extends BaseEntity implements Serializable { - /** - * @Column(type="integer") - */ - private $stockLevel; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\Part\Part") - */ - private $part; - - /** - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\User\User") - */ - private $user; - - /** - * @Column(type="decimal",precision=13,scale=4,nullable=true) - * @var float - */ - private $price; - - /** - * @Column(type="datetime") - * @var DateTime - */ - private $dateTime; - - /** - * Indicates if the stock level is a correction entry. - * - * @Column(type="boolean") - * @var boolean - */ - private $correction; - - /** - * @Column(type="string",nullable=true) - * @var string - */ - private $comment; - - - /** - * Creates a new stock entry. A stock entry tracks how many parts - * were the stockLevel is the amount of items added/removed, - * by which user and how much the user paid for it (for adding parts only!) - * - * @param Part $part The part which was added/removed - * @param int $stockLevel The stock level. Positive value means added parts, negative values means removed parts. - * @param User $user The user who removed/added parts - */ - public function __construct (Part $part, $stockLevel, User $user = null) { - $this->setPart($part); - $this->setStockLevel($stockLevel); - $this->setUser($user); - $this->setDateTime(new \DateTime()); - $this->setCorrection(false); - } - - - /** - * Sets the date+time - * @param \DateTime $dateTime The date+time - */ - private function setDateTime (\DateTime $dateTime) { - $this->dateTime = $dateTime; - } - - /** - * Returns the date+time when the record was created. - * @return \DateTime The date+time when the record was created - */ - public function getDateTime () { - return $this->dateTime; - } - - /** - * Sets if the stock entry is a correction record. - * @param $bCorrection boolean True if the record is a correction record, false otherwise - */ - public function setCorrection ($bCorrection) { - $this->correction = $bCorrection; - } - - /** - * Returns if the entry is a correction entry. - * @return boolean True if the entry is a correction entry, false otherwise - */ - public function getCorrection () { - return $this->correction; - } - - /** - * Sets the price for the item stored. - * - * Please note that the price is for a single item only, and can be null. - * @param float $price The price to set - */ - public function setPrice ($price) { - $this->price = $price; - } - - /** - * Returns the price for this entry. The price is for a single item only. - * - * @return float The price for this entry. - */ - public function getPrice () { - return $this->price; - } - - /** - * Sets the stock level for this entry. - * - * Negative values means part removal, positive values means part adding. - * @param int $stockLevel The stock level - */ - public function setStockLevel($stockLevel) { - $this->stockLevel = $stockLevel; - } - - /** - * Returns the stock level for this entry. - * @return int The stock level - */ - public function getStockLevel () { - return $this->stockLevel; - } - - /** - * Sets the part assigned to this entry. - * @param Part $part The part to set - */ - public function setPart (Part $part) { - $this->part = $part; - } - - /** - * Returns the part assigned to this entry. - * @return Part $part The part - */ - public function getPart () { - return $this->part; - } - - /** - * Sets the user assigned to this entry. - * @param User $user The user The user to set - */ - public function setUser (User $user = null) { - $this->user = $user; - } - - /** - * Returns the user for this entry - * @return User the user - */ - public function getUser () { - return $this->user; - } - - /** - * If the stock level is negative, we can't have a price. - * @PrePersist - */ - public function checkPrice () { - if ($this->getStockLevel() < 0 && $this->getPrice() !== null) { - $this->setPrice(null); - } - } - - /** - * Updates the stock leve for a part - * @PostPersist - */ - public function postPersist () { - $this->part->updateStockLevel(); - $this->part->updatePrice(); - } - - /** - * Returns if the current stock entry is a removal. - * @return boolean True if the entry is a removal, false otherwise - */ - public function isRemoval () { - if ($this->getStockLevel() < 0) { - return true; - } else { - return false; - } - } - - /** - * Sets a comment - * @param string $comment - */ - public function setComment ($comment) { - $this->comment = $comment; - } - - /** - * Returns the comment - * @return string The comment - */ - public function getComment () { - return $this->comment; - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "id" => $this->getId(), - "part_name" => $this->getPart()->getName(), - "part_id" => $this->getPart()->getId(), - "storageLocation_name" => $this->getPart()->getStorageLocation()->getName(), - "username" => is_object($this->getUser()) ? $this->getUser()->getUsername() : PartKeepr::i18n("Unknown User"), - "user_id" => is_object($this->getUser()) ? $this->getUser()->getId() : null, - "stockLevel" => abs($this->getStockLevel()), - "comment" => $this->getComment(), - "dateTime" => $this->getDateTime()->format("Y-m-d H:i:s"), - "direction" => ($this->getStockLevel() < 0) ? "out" : "in", - "price" => $this->getPrice() - ); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Stock/StockManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Stock/StockManager.php @@ -1,66 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Stock; - -use de\RaumZeitLabor\PartKeepr\Manager\AbstractManager, - Doctrine\ORM\QueryBuilder, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class StockManager extends AbstractManager { - /** - * Returns the FQCN for the target entity to operate on. - * @return string The FQCN, e.g. de\RaumZeitLabor\PartKeepr\Part - */ - public function getEntityName () { - return 'de\RaumZeitLabor\PartKeepr\Stock\StockEntry'; - } - - /** - * 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(); - } - - /** - * Returns the default sort field - * - * @return string The default sort field - */ - public function getDefaultSortField () { - return "dateTime"; - } - - /** - * Applies a custom query to the QueryBuilder - * - * @param QueryBuilder $qb The query builder - * @param ManagerFilter $filter The query filter - */ - protected function applyCustomQuery (QueryBuilder $qb, ManagerFilter $filter) { - - // Apply special handling for non-direct fields in relations, where the frontend has no idea about. - foreach ($filter->getSorters() as $sorter) { - switch ($sorter->getSortField()) { - case "q.part_name": - $qb->join("q.part", "p"); - $sorter->setSortField("p.name"); - break; - case "q.user_id": - $qb->leftJoin("q.user", "u"); - $sorter->setSortField("u.username"); - break; - case "q.direction": - $sorter->setSortField("q.dateTime"); - break; - case "q.storageLocation_name": - $qb->join("q.part", "p")->join("p.storageLocation", "st"); - $sorter->setSortField("st.name"); - break; - default: - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Stock/StockService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Stock/StockService.php @@ -1,93 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Stock; - -use de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter, - de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service; - -class StockService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - return array("data" => StockManager::getInstance()->getEntity($this->getParameter("id"))->serialize()); - } else { - $parameters = new ManagerFilter($this); - $parameters->setFilterField("name"); - - if ($this->hasParameter("part")) { - $parameters->setFilterCallback(array($this, "filterCallback")); - } - return StockManager::getInstance()->getList($parameters); - } - } - - /** - * If the "part" parameter is set, join the part into the result and filter on that - * @param QueryBuilder The $queryBuilder - */ - public function filterCallback ($queryBuilder) { - $queryBuilder->andWhere("q.part = :part"); - $queryBuilder->setParameter("part", $this->getParameter("part")); - } - - public function create () { - throw new \Exception("Not yet implemented"); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - $this->requireParameter("id"); - - $stockEntry = StockEntry::loadById($this->getParameter("id")); - - if (!SessionManager::getCurrentSession()->getUser()->isAdmin() && - !(SessionManager::getCurrentSession()->getUser() && $stockEntry->getUser() && SessionManager::getCurrentSession()->getUser()->getId() == $stockEntry->getUser()->getId() )) { - throw new \Exception("Permission denied"); - } - - /* It's not allowed to edit a price for a removal */ - if (!$stockEntry->isRemoval()) { - $stockEntry->setPrice(abs($this->getParameter("price"))); - } - - /** - * Only an admin user may correct the in&out stock levels - */ - if (SessionManager::getCurrentSession()->getUser()->isAdmin()) { - if ($this->getParameter("direction") == "out") { - $stockEntry->setStockLevel(-(abs($this->getParameter("stockLevel")))); - } else { - $stockEntry->setStockLevel($this->getParameter("stockLevel")); - } - - } - - if (SessionManager::getCurrentSession()->getUser()->isAdmin()) { - try { - $stockEntry->setUser(User::loadById($this->getParameter("user_id"))); - } catch (\Exception $e) { - $stockEntry->setUser(null); - } - - } - - $stockEntry->setComment($this->getParameter("comment")); - PartKeepr::getEM()->flush(); - - return array("data" => $stockEntry->serialize()); - } - - public function destroy () { - throw new \Exception("Not yet implemented"); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/Exceptions/StorageLocationNotFoundException.php b/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/Exceptions/StorageLocationNotFoundException.php @@ -1,12 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\StorageLocation\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class StorageLocationNotFoundException extends SerializableException { - public function __construct () { - parent::__construct(PartKeepr::i18n("Storage Location not found.")); - } -} -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocation.php b/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocation.php @@ -1,105 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\StorageLocation; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity; - -/** @Entity **/ -class StorageLocation extends BaseEntity implements Serializable, Deserializable { - /** - * Holds the name for our storage location - * @Column(type="string",unique=true) - * @var string - */ - private $name; - - /** - * Holds the storage location image - * @OneToOne(targetEntity="de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationImage",mappedBy="storageLocation",cascade={"persist", "remove"}) - * @var StorageLocationImage - */ - private $image; - - /** - * Sets the name for the storage location - * @param string $name the name to set - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name of the storage location - * @return string The name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the storage location image - * @param StorageLocationImage $image The storage location image - */ - public function setImage (StorageLocationImage $image) { - $this->image = $image; - $image->setStorageLocation($this); - } - - /** - * Returns the storage location image - * @return StorageLocationImage The storage location image - */ - public function getImage () { - return $this->image; - } - - /** - * Returns this storage location in serialized form - * @return array The serialized storage location - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "image_id" => is_object($this->getImage()) ? $this->getImage()->getId() : null); - } - - /** - * Deserializes the storage location - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "image_id": - if ($value == "") { - echo "/** Breaking because of empty value */"; - break; - } - - try { - $image = StorageLocationImage::loadById($value); - $this->setImage($image); - } catch (\Exception $e) { - if ($this->getImage()) { - // Image was not found, maybe a temporary image? - $this->getImage()->replaceFromTemporaryFile($value); - } else { - $image = StorageLocationImage::createFromTemporaryFile($value); - $this->setImage($image); - echo "/**"; - echo $image->getId(); - echo "*/"; - echo "/** FOO */"; - } - } - - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationImage.php b/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationImage.php @@ -1,50 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\StorageLocation; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Image\Image; - -/** - * Holds a storage location image - * @Entity - **/ -class StorageLocationImage extends Image implements Serializable { - /** - * The storage location object - * @OneToOne(targetEntity="de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation",inversedBy="image") - * @var StorageLocation - */ - private $storageLocation = null; - - /** - * Creates a new storage location image instance - */ - public function __construct () { - parent::__construct(Image::IMAGE_STORAGELOCATION); - } - - /** - * Sets the storage location - * @param StorageLocation $storageLocation The storage location to set - */ - public function setStorageLocation (StorageLocation $storageLocation) { - $this->storageLocation = $storageLocation; - } - - /** - * Returns the storage location - * @return StorageLocation the storage location - */ - public function getStorageLocation () { - return $this->storageLocation; - } - - /** - * - * Serializes this storage location image - * @return array The serialized storage location image - */ - public function serialize () { - return array("id" => $this->getId(), "storageLocation_id" => $this->getStorageLocation()->getId()); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationManager.php @@ -1,94 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\StorageLocation; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, - de\RaumZeitLabor\PartKeepr\StorageLocation\Exceptions\StorageLocationNotFoundException; - -class StorageLocationManager extends Singleton { - public function getStorageLocations ($start = 0, $limit = 10, $sort = "footprint", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st.id, st.name")->from("de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation","st"); - - if ($filter != "") { - $qb = $qb->where("LOWER(st.name) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.name) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "start" => $start, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - public function getStorageLocation ($id) { - $storageLocation = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation", $id); - - if ($storageLocation) { - return $storageLocation; - } else { - throw new StorageLocationNotFoundException(); - } - } - - public function getStorageLocationByName ($name) { - $query = PartKeepr::getEM()->createQuery("SELECT s FROM de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocation s WHERE s.name = :name"); - $query->setParameter("name", $name); - - return $query->getSingleResult(); - } - - public function addStorageLocation ($name) { - $storageLocation = new StorageLocation(); - $storageLocation->setName($name); - - PartKeepr::getEM()->persist($storageLocation); - PartKeepr::getEM()->flush(); - - return $storageLocation; - } - public function deleteStorageLocation ($id) { - $storageLocation = $this->getStorageLocation($id); - - PartKeepr::getEM()->remove($storageLocation); - PartKeepr::getEM()->flush(); - } - - public function getOrCreateStorageLocation ($storageLocation) { - if (is_int($storageLocation)) { - try { - return $this->getStorageLocation($storageLocation); - } catch (StorageLocationNotFoundException $e) {} - } - - $sl = new StorageLocation(); - $sl->setName($storageLocation); - - PartKeepr::getEM()->persist($sl); - - return $sl; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationService.php b/src/backend/de/RaumZeitLabor/PartKeepr/StorageLocation/StorageLocationService.php @@ -1,108 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\StorageLocation; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\Part\PartManager, - de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\Stock\StockEntry, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class StorageLocationService extends Service implements RestfulService { - - public function get () { - if ($this->hasParameter("id")) { - return array("data" => StorageLocationManager::getInstance()->getStorageLocation($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "name", - "direction" => "ASC"); - } - return StorageLocationManager::getInstance()->getStorageLocations( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - public function create () { - $this->requireParameter("name"); - - $storageLocation = new StorageLocation(); - $storageLocation->deserialize($this->getParameters()); - - PartKeepr::getEM()->persist($storageLocation); - - try { - PartKeepr::getEM()->flush(); - } catch (\PDOException $e) { - if ($e->getCode() == "23505") { - $exception = new SerializableException(sprintf(PartKeepr::i18n("Storage Location %s already exists!"), $storageLocation->getName())); - $exception->setDetail(sprintf(PartKeepr::i18n("You tried to add the storage location %s, but a storage location with the same name already exists."), $storageLocation->getName())); - - throw $exception; - } else { - throw $e; - } - } - - - return array("data" => $storageLocation->serialize()); - } - - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - $storageLocation = StorageLocationManager::getInstance()->getStorageLocation($this->getParameter("id")); - $storageLocation->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $storageLocation->serialize()); - - } - - public function destroy () { - $this->requireParameter("id"); - - StorageLocationManager::getInstance()->deleteStorageLocation($this->getParameter("id")); - - return array("data" => null); - } - - /** - * Creates multiple storage locations at once. - * - * Requires that the parameter "storageLocations" is set to an array with the names of the storage locations. - * Returns all error messages as "data" index in the result array. - */ - public function massCreate () { - $this->requireParameter("storageLocations"); - - $aMessages = array(); - - foreach ($this->getParameter("storageLocations") as $storageLocation) { - try { - $obj = StorageLocationManager::getInstance()->getStorageLocationByName($storageLocation); - $aMessages[] = sprintf(PartKeepr::i18n("Storage Location %s already exists"), $storageLocation); - } catch (\Exception $e) { - $obj = new StorageLocation(); - $obj->setName($storageLocation); - PartKeepr::getEM()->persist($obj); - } - - } - - PartKeepr::getEM()->flush(); - - return array("data" => $aMessages); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/System/SystemInformationRecord.php b/src/backend/de/RaumZeitLabor/PartKeepr/System/SystemInformationRecord.php @@ -1,55 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\System; - -/** - * This class represents a system information record. - * - * This is basically a category, a name and a value. No logic included within - * the class. - * - * For example, records could hold: - * - * Name Value Category - * ===================================================================================== - * Doctrine ORM 2.1.0 Libraries - * Doctrine DBAL 2.1.0 Libraries - * Doctrine Migrations git-f87afe9223dbfecaaddb Libraries - * - * PHP Version 5.3.2 Server Software - * Operating System Linux (Funtoo Linux - baselayout 2.1.8) Server Software - - * @author felicitus - * - */ -class SystemInformationRecord { - /** - * Holds the category name - * @var string - */ - public $category; - - /** - * Holds the name - * @var string - */ - public $name; - - /** - * Holds the value - * @var mixed - */ - public $value; - - /** - * Creates a new system information record. - * - * @param string $name - * @param mixed $value - * @param string $category - */ - public function __construct ($name, $value, $category) { - $this->name = $name; - $this->value = $value; - $this->category = $category; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/System/SystemService.php b/src/backend/de/RaumZeitLabor/PartKeepr/System/SystemService.php @@ -1,99 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\System; - -use de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\CronLogger\CronLoggerManager, - de\RaumZeitLabor\PartKeepr\Util\OS\OperatingSystem; - -class SystemService extends Service { - /** - * Returns a list of system information records. - * - * Please note that it is not defined which information is returned; the result - * should be seen as "informational" to the system operator, not for automated purposes. - */ - public function getSystemInformation () { - $aData = array(); - - $aData[] = new SystemInformationRecord("Doctrine ORM", \Doctrine\ORM\Version::VERSION, "Libraries"); - $aData[] = new SystemInformationRecord("Doctrine DBAL", \Doctrine\DBAL\Version::VERSION, "Libraries"); - - $aData[] = new SystemInformationRecord("PHP Version", phpversion(), "System"); - - $os = new OperatingSystem(); - - $aData[] = new SystemInformationRecord("Operating System Type", $os->getPlatform(), "System"); - $aData[] = new SystemInformationRecord("Operating System Release", $os->getRelease(), "System"); - - $aData[] = new SystemInformationRecord("memory_limit", ini_get("memory_limit"), "PHP"); - $aData[] = new SystemInformationRecord("post_max_size", ini_get("post_max_size"), "PHP"); - $aData[] = new SystemInformationRecord("upload_max_filesize", ini_get("upload_max_filesize"), "PHP"); - $aData[] = new SystemInformationRecord("post_max_size", ini_get("post_max_size"), "PHP"); - $aData[] = new SystemInformationRecord("allow_url_fopen", ini_get("allow_url_fopen"), "PHP"); - $aData[] = new SystemInformationRecord("max_execution_time", ini_get("max_execution_time"), "PHP"); - $aData[] = new SystemInformationRecord("APC enabled", (extension_loaded("apc") ? PartKeepr::i18n("Yes") : PartKeepr::i18n("No")), "PHP"); - - $aData[] = new SystemInformationRecord("PartKeepr Version", PartKeepr::getVersion(), "PartKeepr"); - - - foreach (Configuration::getOptions() as $key => $value) { - - // Hide passwords - if ($key == "partkeepr.database.password" || $key == "partkeepr.migration.partdb.password") { - $value = "<hidden>"; - } - - $aData[] = new SystemInformationRecord($key, $value, "PartKeepr Configuration Information"); - } - - return array("data" => $aData); - } - - /** - * Returns the database schema status. - * - * This method is usuall called once the user logs in, and alerts him if the schema is not up-to-date. - * - * Returns either status incomplete if the schema is not up-to-date, or complete if everything is OK. - */ - public function getSystemStatus () { - - if (Configuration::getOption("partkeepr.cronjobs.disablecheck", false) === true) { - // Skip cronjob tests - $inactiveCronjobs = array(); - } else { - $inactiveCronjobs = CronLoggerManager::getInstance()->getInactiveCronjobs(); - } - - - return array("data" => - array( - "inactiveCronjobCount" => count($inactiveCronjobs), - "inactiveCronjobs" => $inactiveCronjobs, - "schemaStatus" => $this->getSchemaStatus())); - } - - /** - * Checks if the schema is up-to-date. If yes, it returns "complete", if not, it returns "incomplete". - * - * @param none - * @return string Either "complete" or "incomplete" - */ - protected function getSchemaStatus () { - $metadatas = PartKeepr::getEM()->getMetadataFactory()->getAllMetadata(); - - $schemaTool = new \Doctrine\ORM\Tools\SchemaTool(PartKeepr::getEM()); - - $queries = $schemaTool->getUpdateSchemaSql($metadatas, true); - - if (count($queries) > 0) { - return "incomplete"; - } else { - return "complete"; - } - } - - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNotice.php b/src/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNotice.php @@ -1,141 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\SystemNotice; - -use de\RaumZeitLabor\PartKeepr\UploadedFile\UploadedFile, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\Deserializable; - -/** - * Holds a system notice - * @Entity - **/ -class SystemNotice extends BaseEntity implements Serializable { - /** - * @Column(type="datetime") - * @var \DateTime - */ - private $date; - - /** - * @Column(type="string") - * @var string - */ - private $title; - - /** - * The description of this attachment - * @Column(type="text") - * @var string - */ - private $description; - - /** - * Defines if the system notice has been acknowledged - * @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. - * @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/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNoticeManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNoticeManager.php @@ -1,55 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\SystemNotice; - -use de\RaumZeitLabor\PartKeepr\Manager\AbstractManager, - de\RaumZeitLabor\PartKeepr\Project\Project, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class SystemNoticeManager extends AbstractManager { - /** - * Returns the FQCN for the target entity to operate on. - * @return string The FQCN, e.g. de\RaumZeitLabor\PartKeepr\Part - */ - public function getEntityName () { - return 'de\RaumZeitLabor\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 de\RaumZeitLabor\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/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNoticeService.php b/src/backend/de/RaumZeitLabor/PartKeepr/SystemNotice/SystemNoticeService.php @@ -1,83 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\SystemNotice; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Manager\ManagerFilter; - -class SystemNoticeService extends Service implements RestfulService { - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\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 de\RaumZeitLabor\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 de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - throw new \Exception("Not implemented"); - - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\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 de\RaumZeitLabor\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 diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/TempFile/TempFileService.php b/src/backend/de/RaumZeitLabor/PartKeepr/TempFile/TempFileService.php @@ -1,72 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\TempFile; - -use de\RaumZeitLabor\PartKeepr\Service\Service; -use de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile; -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -class TempFileService extends Service { - - public function upload () { - $tmpFile = new TempUploadedFile(); - - if (array_key_exists("userfile", $_FILES) && file_exists($_FILES["userfile"]["tmp_name"])) { - $file = $_FILES['userfile']['tmp_name']; - $filename = $_FILES['userfile']['name']; - - $tmpFile->replace($file); - $tmpFile->setOriginalFilename(basename($filename)); - } elseif (array_key_exists("url", $_REQUEST)) { - $tmpFile->replaceFromURL($_REQUEST["url"]); - } else { - throw new \Exception("Error: No valid file given"); - } - - PartKeepr::getEM()->persist($tmpFile); - PartKeepr::getEM()->flush(); - - return array("id" => $tmpFile->getId(), "extension" => $tmpFile->getExtension(), "size" => $tmpFile->getSize(), "originalFilename" => $tmpFile->getOriginalFilename()); - } - - /** - * Receives a file via the service call. - * - * Parameters: - * - filedata: needs to be base64-encoded. - * - filename: The filename - */ - public function jsonUpload () { - $data = base64_decode($this->getParameter("filedata")); - $filename = $this->getParameter("filename"); - - $tempFile = tempnam("/tmp", "PWC"); - file_put_contents($tempFile, $data); - - $tmpFile = new TempUploadedFile(); - $tmpFile->replace($tempFile); - $tmpFile->setOriginalFilename($filename); - - PartKeepr::getEM()->persist($tmpFile); - PartKeepr::getEM()->flush(); - - return $tmpFile->serialize(); - } - - /** - * Processes data via HTTP POST. Reads php://input and creates a temporary image out of it. - */ - public function uploadCam () { - $tempFile = tempnam("/tmp", "PWC") . ".jpg"; - $result = file_put_contents( $tempFile, file_get_contents('php://input') ); - - $image = new TempUploadedFile(); - $image->replace($tempFile); - $image->setOriginalFilename(sprintf(PartKeepr::i18n("Cam photo of %s"), date("Y-m-d H:i:s")).".jpg"); - - PartKeepr::getEM()->persist($image); - PartKeepr::getEM()->flush(); - - return array("id" => $image->getId(), "extension" => $image->getExtension(), "size" => $image->getSize(), "originalFilename" => $image->getOriginalFilename()); - } -} - - \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/TempImage/TempImage.php b/src/backend/de/RaumZeitLabor/PartKeepr/TempImage/TempImage.php @@ -1,19 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\TempImage; - -use de\RaumZeitLabor\PartKeepr\Image\Exceptions\InvalidImageTypeException, - de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\Image\Image, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Represents a temporary image. Temporary images are used when - * a user uploaded an image, but not attached it to an entity. - * - * @Entity - */ -class TempImage extends Image { - public function __construct () { - parent::__construct(Image::IMAGE_TEMP); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/TempImage/TempImageService.php b/src/backend/de/RaumZeitLabor/PartKeepr/TempImage/TempImageService.php @@ -1,30 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\TempImage; - -use de\RaumZeitLabor\PartKeepr\Service\Service; -use de\RaumZeitLabor\PartKeepr\TempImage\TempImage; -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -class TempImageService extends Service { - public function upload () { - $image = new TempImage(); - - if (array_key_exists("userfile", $_FILES) && file_exists($_FILES["userfile"]["tmp_name"])) { - $file = $_FILES['userfile']['tmp_name']; - $filename = $_FILES['userfile']['name']; - - $image->replace($file); - $image->setOriginalFilename(basename($filename)); - } elseif (array_key_exists("url", $_REQUEST)) { - $image->replaceFromURL($_REQUEST["url"]); - } else { - throw new \Exception("Error: No valid file given"); - } - - PartKeepr::getEM()->persist($image); - PartKeepr::getEM()->flush(); - - return array("id" => $image->getId(), "extension" => $image->getExtension(), "size" => $image->getSize(), "originalFilename" => $image->getOriginalFilename()); - } -} - - \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDay.php b/src/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDay.php @@ -1,114 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\TipOfTheDay; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -use de\RaumZeitLabor\PartKeepr\Util\Configuration; - -use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; - -/** - * Represents a tip of the day. - * - * Tips are stored on the central PartKeepr server in a wiki. However, we need to know a list of all tip pages - * because the API has a limit per day. So basically, we sync the tip names from the wiki to the local system several - * times a day and not each time an user logs in. - * - * Note: If you wish to link against a tip of the day, do it by name and not by id! - * - * @Entity - **/ -class TipOfTheDay extends BaseEntity implements Serializable { - /** - * @Column(type="string") - * @var string - */ - private $name; - - /** - * Sets the name for this tip - * @param string $name The name - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name for this tip - * @return string The name - */ - public function getName () { - return $this->name; - } - - /** - * Syncronizes the tip database against the master wiki. - * @throws \Exception - */ - public static function syncTips () { - if (ini_get("allow_url_fopen") == 0) { - throw new \Exception("allow_url_fopen is disabled, but required to query the TipOfTheDay database."); - } - - $url = Configuration::getOption("partkeepr.tipoftheday.api", "http://partkeepr.org/wiki/api.php?action=query&list=categorymembers&cmtitle=Category:TipOfTheDay&format=json"); - - $tipsString = file_get_contents($url); - - - $aPageNames = self::extractPageNames($tipsString); - - self::updateTipDatabase($aPageNames); - } - - /** - * Updates the tip database. Expects an array of page names. - * - * This method clears all page names and re-creates them. This saves - * alot of engineering, because we don't need to match contents - * within the database against contents in an array. - * - * @param array $aPageNames The page names as array. Page names are stored as string. - */ - private static function updateTipDatabase (array $aPageNames) { - $dql = "DELETE FROM de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDay"; - $query = PartKeepr::getEM()->createQuery($dql); - - $query->execute(); - - foreach ($aPageNames as $pageName) { - $tip = new TipOfTheDay(); - $tip->setName($pageName); - PartKeepr::getEM()->persist($tip); - } - - PartKeepr::getEM()->flush(); - } - - /** - * Extracts the page names from the mediawiki JSON returned. - * @param string $response The encoded json string - * @return array An array with the titles of each page - */ - private static function extractPageNames ($response) { - $aTipsStructure = json_decode($response, true); - $aTips = $aTipsStructure["query"]["categorymembers"]; - - $aPageNames = array(); - - foreach ($aTips as $tip) { - $aPageNames[] = $tip["title"]; - } - - return $aPageNames; - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( "name" => $this->getName() ); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDayHistory.php b/src/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDayHistory.php @@ -1,51 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\TipOfTheDay; - -use de\RaumZeitLabor\PartKeepr\User\User; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -use de\RaumZeitLabor\PartKeepr\Util\Configuration; - -use de\RaumZeitLabor\PartKeepr\Util\BaseEntity; - -/** - * Represents a tip of the day history entry. - * - * This entity stores each tip of the day the user has already seen. - * - * @Entity - **/ -class TipOfTheDayHistory extends BaseEntity { - /** - * @Column(type="string") - * @var string - */ - private $name; - - /** - * Defines the user - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\User\User") - * @var StorageLocation - */ - private $user; - - /** - * Sets the user for this entry - * @param User $user - */ - public function setUser (User $user) { - $this->user = $user; - } - - /** - * Sets the tip of the day name the user already has seen - * @param string $name The tip name - */ - public function setName ($name) { - $this->name = $name; - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDayService.php b/src/backend/de/RaumZeitLabor/PartKeepr/TipOfTheDay/TipOfTheDayService.php @@ -1,86 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\TipOfTheDay; - -use de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -class TipOfTheDayService extends Service implements RestfulService { - /** - * Returns all tips along with the information wether they are read or not. - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - $aTips = array(); - $url = Configuration::getOption("partkeepr.tipoftheday.wiki", "http://partkeepr.org/wiki/index.php/"); - - /* Extract all tips which aren't read */ - $dql = "SELECT d FROM de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDay d WHERE d.name NOT IN "; - $dql .= "(SELECT dh.name FROM de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDayHistory dh WHERE dh.user = :user)"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", SessionManager::getCurrentSession()->getUser()); - - foreach ($query->getResult() as $result) { - $aTips[] = array ( - "name" => $result->getName(), - "read" => false, - "url" => $url.$result->getName() . "?useskin=monobookplain"); - } - - /* Extract all tips which are read */ - $dql = "SELECT d FROM de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDay d WHERE d.name IN "; - $dql .= "(SELECT dh.name FROM de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDayHistory dh WHERE dh.user = :user)"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", SessionManager::getCurrentSession()->getUser()); - - foreach ($query->getResult() as $result) { - $aTips[] = array ( - "name" => $result->getName(), - "read" => true, - "url" => $url.$result->getName() . "?useskin=monobookplain"); - } - - return array("data" => $aTips); - } - - public function create() {} - public function update () {} - public function destroy () {} - - /** - * Marks a specific tip as read. - * - * Uses the parameter "name" to identify the tip. - */ - public function markTipAsRead () { - $this->requireParameter("name"); - - try { - $th = new TipOfTheDayHistory; - $th->setUser($this->getUser()); - $th->setName($this->getParameter("name")); - - PartKeepr::getEM()->persist($th); - PartKeepr::getEM()->flush(); - } catch (\Exception $e) { - /* Do nothing */ - } - - } - - /** - * Marks all tips as unread for the current user - */ - public function markAllTipsAsUnread () { - $dql = "DELETE FROM de\RaumZeitLabor\PartKeepr\TipOfTheDay\TipOfTheDayHistory th WHERE th.user = :user"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", $this->getUser()); - $query->execute(); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Unit/Unit.php b/src/backend/de/RaumZeitLabor/PartKeepr/Unit/Unit.php @@ -1,130 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Unit; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Exceptions\OutOfRangeException, - de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix; - - -/** - * This object represents an unit. Units can be: Volt, Hertz etc. - * - * @Entity - **/ -class Unit extends BaseEntity implements Serializable, Deserializable { - /** - * The name of the unit (e.g. Volts, Ampere, Farad, Metres) - * @Column(type="string") - * @var string - */ - private $name; - - /** - * The symbol of the unit (e.g. V, A, F, m) - * @Column(type="string") - * @var string - */ - private $symbol; - - /** - * Defines the allowed SiPrefixes for this parameter unit - * @ManyToMany(targetEntity="de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix") - * @JoinTable(name="UnitSiPrefixes", - * joinColumns={@JoinColumn(name="unit_id", referencedColumnName="id")}, - * inverseJoinColumns={@JoinColumn(name="siprefix_id", referencedColumnName="id")} - * ) - * @var ArrayCollection - */ - private $prefixes; - - /** - * Creates a new Unit. - */ - public function __construct () { - $this->prefixes = new \Doctrine\Common\Collections\ArrayCollection(); - } - - /** - * Sets the name for this unit - * @param string $name the name for this unit - */ - public function setName ($name) { - $this->name = $name; - } - - /** - * Returns the name for this unit - * @return string The unit name - */ - public function getName () { - return $this->name; - } - - /** - * Sets the symbol for this unit - * @param string $symbol The symbol - */ - public function setSymbol ($symbol) { - $this->symbol = $symbol; - } - - /** - * Returns the symbol for this unit - * @return string The symbol - */ - public function getSymbol () { - return $this->symbol; - } - - /** - * Returns the si-prefix list for this unit - * @return array An array of SiPrefix objects - */ - public function getPrefixes () { - return $this->prefixes; - } - - /** - * Serializes the user object and returns it as array, suitable - * to process via json_encode. - * @param none - * @return array An array containing the object information - */ - public function serialize () { - return array( - "id" => $this->getId(), - "name" => $this->getName(), - "symbol" => $this->getSymbol(), - "prefixes" => $this->serializeChildren($this->getPrefixes()) - ); - } - - /** - * Deserializes the unit - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "name": - $this->setName($value); - break; - case "symbol": - $this->setSymbol($value); - break; - case "prefixes": - $prefixes = $this->getPrefixes(); - $prefixes->clear(); - - foreach ($value as $prefix) { - $prefix = SiPrefix::loadById($prefix["id"]); - $prefixes->add($prefix); - } - break; - } - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Unit/UnitManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/Unit/UnitManager.php @@ -1,99 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Unit; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Unit\Exceptions\UnitNotFoundException; - -class UnitManager extends Singleton { - public function getUnits ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("u.id, u.name, u.symbol")->from("de\RaumZeitLabor\PartKeepr\Unit\Unit","u"); - - if ($filter != "") { - $qb = $qb->where("LOWER(u.name) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("u.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(u.id)")->from("de\RaumZeitLabor\PartKeepr\Unit\Unit","u"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(u.name) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - foreach ($result as $key => $value) { - $result[$key]["prefixes"] = $this->getSiPrefixes($value["id"]); - } - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - public function getSiPrefixes ($id) { - $unit = UnitManager::getInstance()->getUnit($id); - - $aData = array(); - - foreach ($unit->getPrefixes() as $prefix) { - $aData[] = $prefix->serialize(); - } - - return array("response" => array("totalCount" => count($aData), "data" => $aData)); - } - - public function getUnitByName ($name) { - $dql = "SELECT u FROM de\RaumZeitLabor\PartKeepr\Unit\Unit u WHERE u.name = :name"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $name); - - return $query->getSingleResult(); - } - - public function unitExists ($name) { - $dql = "SELECT COUNT(u) FROM de\RaumZeitLabor\PartKeepr\Unit\Unit u WHERE u.name = :name"; - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $name); - - if ($query->getSingleScalarResult() == 0) { - return false; - } else { - return true; - } - } - - public function getUnit ($id) { - $unit = PartKeepr::getEM()->find("de\RaumZeitLabor\PartKeepr\Unit\Unit", $id); - - if ($unit) { - return $unit; - } else { - throw new UnitNotFoundException(); - } - } - - public function deleteUnit ($id) { - $unit = $this->getUnit($id); - - PartKeepr::getEM()->remove($unit); - PartKeepr::getEM()->flush(); - } - - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Unit/UnitService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Unit/UnitService.php @@ -1,67 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Unit; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\PartUnit, - de\RaumZeitLabor\PartKeepr\SiPrefix\SiPrefix, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class UnitService extends Service implements RestfulService { - public function get () { - if ($this->hasParameter("id")) { - return array("data" => UnitManager::getInstance()->getUnit($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "name", - "direction" => "ASC"); - } - return UnitManager::getInstance()->getUnits( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - public function create () { - $this->requireParameter("name"); - - $unit = new Unit; - $unit->deserialize($this->getParameters()); - - PartKeepr::getEM()->persist($unit); - PartKeepr::getEM()->flush(); - - return array("data" => $unit->serialize()); - } - - public function update () { - $this->requireParameter("id"); - $this->requireParameter("name"); - - $unit = UnitManager::getInstance()->getUnit($this->getParameter("id")); - $unit->deserialize($this->getParameters()); - - PartKeepr::getEM()->flush(); - - return array("data" => $unit->serialize()); - - } - - public function destroy () { - $this->requireParameter("id"); - - UnitManager::getInstance()->deleteUnit($this->getParameter("id")); - - return array("data" => null); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/UploadedFile/TempUploadedFile.php b/src/backend/de/RaumZeitLabor/PartKeepr/UploadedFile/TempUploadedFile.php @@ -1,15 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\UploadedFile; - -/** - * Represents a temporary file. Temporary files are used when - * a user uploaded a file, but not attached it to an entity. - * - * @Entity - */ -class TempUploadedFile extends UploadedFile { - public function __construct () { - parent::__construct(); - $this->setType("Temporary"); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/UploadedFile/UploadedFile.php b/src/backend/de/RaumZeitLabor/PartKeepr/UploadedFile/UploadedFile.php @@ -1,301 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\UploadedFile; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile, - de\RaumZeitLabor\PartKeepr\Util\Configuration; - -/** - * @MappedSuperclass - */ -abstract class UploadedFile extends BaseEntity implements Serializable { - /** - * Specifies the type of the file. - * - * @var string - * @Column(type="string") - **/ - private $type; - - /** - * The unique filename of the file - * - * @var string - * @Column(type="string") - */ - private $filename; - - /** - * The original name of the file - * @Column(type="string",nullable=true) - * @var string - */ - private $originalname; - - /** - * The mimetype for the file - * @var string - * @Column(type="string") - */ - private $mimetype; - - /** - * The size of the uploaded file - * @Column(type="integer") - * @var integer - */ - private $size; - - /** - * Constructs a new file object. - * - */ - public function __construct () { - $this->filename = PartKeepr::createGUIDv4(); - } - - /** - * Sets the type of the file. Once the type is set, - * it may not be changed later. - */ - protected function setType ($type) { - $this->type = $type; - } - - /** - * Returns the original filename - * @return string The original filename - */ - public function getOriginalFilename () { - return $this->originalname; - } - - /** - * Sets the original filename - * @param string $filename The original filename - */ - public function setOriginalFilename ($filename) { - $this->originalname = $filename; - } - - /** - * Replaces the current file with a new file. - * - * @param string $path The path to the original file - */ - public function replace ($path) { - // Parse the file's mimetype - $finfo = new \finfo(FILEINFO_MIME); - $this->mimetype = $finfo->file($path, FILEINFO_MIME_TYPE); - - // Get the file size - $this->size = filesize($path); - - $this->ensureFilePathExists(); - $this->checkPermissions(); - - copy($path, $this->getFilename()); - - $this->setOriginalFilename(basename($path)); - } - - /** - * Replaces the file from an URL. Does some tricks to avoid 403 forbidden on some sites. - * @param string $url - */ - public function replaceFromURL ($url) { - - /* Some sites don't like automated requests. But the internet is meant to be open for anybody, - * even for scripts. So we are evil and fake the headers. - * - * Credit goes to Ryan Rampersad from whom I copied most code. - * http://blog.ryanrampersad.com/2008/11/07/get-remote-html-with-curl-and-php/ - */ - $curl = curl_init(); - - $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,"; - $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; - $header[] = "Cache-Control: max-age=0"; - $header[] = "Connection: keep-alive"; - $header[] = "Keep-Alive: 300"; - $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"; - $header[] = "Accept-Language: en-us,en;q=0.5"; - $header[] = "Pragma: "; - - $browser = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3"; - - curl_setopt($curl, CURLOPT_URL, $url); - curl_setopt($curl, CURLOPT_USERAGENT, $browser); - curl_setopt($curl, CURLOPT_HTTPHEADER, $header); - curl_setopt($curl, CURLOPT_AUTOREFERER, true); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_TIMEOUT, 30); - curl_setopt($curl, CURLOPT_MAXREDIRS, 7); - curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); - - $data = curl_exec($curl); - - if ($data === false) { - throw new \Exception("replaceFromURL error: ".curl_error($curl)); - } - - curl_close($curl); - - $tempName = tempnam("/tmp", "PARTKEEPR"); - - file_put_contents($tempName, $data); - - $this->replace($tempName); - - $this->setOriginalFilename(basename($url)); - } - - /** - * Returns the size of this file - * @return integer The size in bytes - */ - public function getSize () { - return $this->size; - } - - /** - * Returns the type of the file - * @param none - * @return string The type of the file - */ - public function getType () { - return $this->type; - } - - /** - * Returns the full filename including path and suffix. - * @return string The full filename - */ - public function getFilename () { - return $this->getFilePath().$this->filename.".".$this->getExtension(); - } - - /** - * Returns the plain filename without path and suffix. - * @return string the plain filename - */ - public function getPlainFilename () { - return $this->filename; - } - - /** - * Returns the mime type for this file - * @return string The mimetype for this file, e.g. text/plain - */ - public function getMimeType () { - return $this->mimetype; - } - - /** - * Returns the extension for the given mime type. - * - * This function simply extracts that information from the mime type; - * special cases are not handled. e.g. if you have image/foobar, it would - * return "foobar" as extension. - * - * @return string The extension - */ - public function getExtension () { - list($category, $type) = explode("/", $this->getMimeType()); - return $type; - } - - /** - * Returns the path to the file. May be overridden by - * subclasses. - * - * @param none - * @return string The path to the file - */ - public function getFilePath () { - return Configuration::getOption( - "partkeepr.files.path", - PartKeepr::getRootDirectory() . "/data/") . $this->getType() . "/"; - } - - /** - * Ensures that the file path exists. This function - * is called every time a file is processed. - * It is maybe a bit overhead, but saves headaches later when - * introducing new types. - * - * @param none - * @return nothing - */ - public function ensureFilePathExists () { - if (!is_dir($this->getFilePath())) { - try { - mkdir($this->getFilePath(), 0777, true); - } catch (\Exception $e) { - throw new \Exception("Unable to create directory ".$this->getFilePath()); - } - } - } - - /** - * Creates a new entity from the given temporary id. - * - * @param string $id The temporary id (prefixed with TMP:) - * @return object a new instance of the file. - * @throws \Exception If the ID does not begin with TMP: - */ - public static function createFromTemporaryFile ($id) { - if (substr($id, 0, 4) === "TMP:") { - // It's a temporary file - $className = get_called_class(); - - $file = new $className(); - $file->replaceFromTemporaryFile($id); - return $file; - } else { - throw new \Exception("Given id $id is not a temporary file"); - } - } - - /** - * Replaces the file with a given temporary file. - * @param string $id The temporary id (prefixed with TMP:) - */ - public function replaceFromTemporaryFile ($id) { - if (substr($id, 0, 4) === "TMP:") { - $tmpFileId = str_replace("TMP:", "", $id); - $tmpFile = TempUploadedFile::loadById($tmpFileId); - - $this->replace($tmpFile->getFilename()); - $this->setOriginalFilename($tmpFile->getOriginalFilename()); - } - } - - /** - * Checks if the path where the file should be stored has sufficient permissions to do so. - * - * @throws SerializableException - */ - public function checkPermissions () { - if (!is_writable($this->getFilePath())) { - throw new SerializableException( - sprintf(PartKeepr::i18n("Unable to write to directory %s"), $this->getFilePath())); - } - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "id" => $this->getId(), - "extension" => $this->getExtension(), - "size" => $this->getSize(), - "originalFilename" => $this->getOriginalFilename() - ); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/InvalidLoginDataException.php b/src/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/InvalidLoginDataException.php @@ -1,14 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\User\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Is thrown when the user has given wrong credentials. - */ -class InvalidLoginDataException extends SerializableException { - public function __construct () { - parent::__construct(PartKeepr::i18n("Username or Password wrong.")); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/UserAlreadyExistsException.php b/src/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/UserAlreadyExistsException.php @@ -1,19 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\User\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** -* Is thrown when the user already exists. This usually happens -* if someone tries to create a user with the same name of an existing -* user. -*/ -class UserAlreadyExistsException extends SerializableException { - public function __construct ($username) { - parent::__construct( - sprintf( - PartKeepr::i18n("User %s already exists."), - $username)); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/UserDoesNotExistException.php b/src/backend/de/RaumZeitLabor/PartKeepr/User/Exceptions/UserDoesNotExistException.php @@ -1,17 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\User\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** -* Is thrown when the user doesn't exist. -*/ -class UserDoesNotExistException extends SerializableException { - public function __construct ($username) { - parent::__construct( - sprintf( - PartKeepr::i18n("The user %s doesn't exist. Maybe the user was already deleted."), - $username)); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/User/User.php b/src/backend/de/RaumZeitLabor/PartKeepr/User/User.php @@ -1,259 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\User; - -use de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference; - -use de\RaumZeitLabor\PartKeepr\Util\Deserializable, - de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** @Entity @Table(name="PartKeeprUser") */ -class User extends BaseEntity implements Serializable, Deserializable { - /** @Column(length=50,unique=true) */ - private $username; - - /** @Column(length=32) */ - private $password; - - /** @Column(type="boolean") */ - private $admin; - - /** - * Creates a new user object. - * - * @param string $username The username to set (optional) - * @param string $password The password to set (optional) - */ - public function __construct ($username = null, $password = null) { - if ($username !== null) { - $this->setUsername($username); - } - - if ($password !== null) { - $this->setPassword($password); - } - - $this->setAdmin(false); - } - - /** - * Sets the username. - * - * Forces the username to have - * lowercase a-z characters. - * - * Replaces space with an underscore. - * Replaces dot with nothing. - * - * @param string $username The username to set. Applies automatic username modification. - * @return nothing - */ - public function setUsername ($username) { - $username = strtolower($username); - $username = str_replace(" ", "_", $username); - $username = str_replace(".", "", $username); - - $this->username = $username; - - } - - /** - * Sets the raw username, without replacing any special chars. - * - * This method should only be used for building a temporary user - * for login checks. - * - * @param string $username The raw username - * @return nothing - */ - public function setRawUsername ($username) { - $this->username = $username; - } - - /** - * Returns the username. - * @param none - * @return string The username - */ - public function getUsername () { - return $this->username; - } - - /** - * Sets the admin flag - * @param boolean $bAdmin True if the user is an admin, false otherwise - */ - public function setAdmin ($bAdmin) { - $this->admin = (boolean)$bAdmin; - } - - /** - * Returns the admin flag - * @return boolean True if the user is an admin - */ - public function isAdmin () { - return $this->admin; - } - - /** - * Sets the user's password. Automatically - * applies md5 hashing. - * - * @param string $password - */ - public function setPassword ($password) { - $this->setHashedPassword(md5($password)); - } - - /** - * Returns the user's md5-hashed password. - * @param none - * @return string The md5-hashed password - */ - public function getHashedPassword () { - return $this->password; - } - - /** - * Sets the user's password. Expects a hash - * and does not apply md5 hasing. - * - * @param string $hashedPassword - */ - public function setHashedPassword ($hashedPassword) { - $this->password = $hashedPassword; - } - - /** - * Compares the given un-hashed password with the - * object's hashed password. - * - * - * @param string $password The unhashed password - * @return boolean true if the passwords match, false otherwise - */ - public function comparePassword ($password) { - return $this->compareHashedPassword(md5($password)); - } - - /** - * Compares the given hashed password with the object's - * hashed password. - * - * @param string $hashedPassword The md5-hashed password - * @return boolean true if the passwords match, false otherwise - */ - public function compareHashedPassword ($hashedPassword) { - if ($hashedPassword == $this->password) { - return true; - } else { - return false; - } - } - - /** - * Serializes the user object and returns it as array, suitable - * to process via json_encode. - * @param none - * @return array An array containing the object information - */ - public function serialize () { - return array( - "id" => $this->getId(), - "username" => $this->getUsername() - ); - } - - /** - * Deserializes the user - * @param array $parameters The array with the parameters to set - */ - public function deserialize (array $parameters) { - foreach ($parameters as $key => $value) { - switch ($key) { - case "username": - $this->setUsername($value); - break; - case "password": - if ($value !== "") { - $this->setPassword($value); - } - break; - } - } - } - - /** - * Sets a user preference - * - * @param string $preferenceKey The preference key - * @param string $preferenceValue The preference value - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public function setPreference ($preferenceKey, $preferenceValue) { - return UserPreference::setPreference($this, $preferenceKey, $preferenceValue); - } - - /** - * Returns a given preference object - * - * @param string $preferenceKey The preference key - * @return UserPreference The user preference object - * @throws UserPreferenceNotFoundException If the preference key was not found - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public function getPreference ($preferenceKey) { - return UserPreference::getPreference($this, $preferenceKey); - } - - /** - * Returns a given preference value - * - * @param string $preferenceKey The preference key - * @return UserPreference The user preference object - * @throws UserPreferenceNotFoundException If the preference key was not found - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public function getPreferenceValue ($preferenceKey) { - return UserPreference::getPreferenceValue($this, $preferenceKey); - } - - /** - * Deletes the given preference - * - * @param string $preferenceKey The preference key - * @return UserPreference The user preference object - * @throws UserPreferenceNotFoundException If the preference key was not found - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public function deletePreference ($preferenceKey) { - return UserPreference::deletePreference($this, $preferenceKey); - } - - /** - * Returns all user preferences for this user - * - * @param none - * @return Array An array of UserPreference objects - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public function getPreferences () { - return UserPreference::getPreferences($this); - } - /** - * Loads a user by name. - * - * @param $username string The username to query - * @return User A user object - * @throws Doctrine\ORM\NoResultException If no user was found - */ - public static function loadByName ($username) { - $dql = "SELECT u FROM de\RaumZeitLabor\PartKeepr\User\User u WHERE u.username = :username"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("username", $username); - - return $query->getSingleResult(); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/User/UserManager.php b/src/backend/de/RaumZeitLabor/PartKeepr/User/UserManager.php @@ -1,135 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\User; - -use de\RaumZeitLabor\PartKeepr\Util\Singleton, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\Exceptions\InvalidLoginDataException, - de\RaumZeitLabor\PartKeepr\Category\CategoryManager, - de\RaumZeitLabor\PartKeepr\User\Exceptions\UserAlreadyExistsException, - de\RaumZeitLabor\PartKeepr\User\Exceptions\UserNotFoundException; - -class UserManager extends Singleton { - /** - * Returns a list of users. - * - * @param int $start Start of the list, default 0 - * @param int $limit Number of users to list, default 10 - * @param string $sort The field to sort by, default "name" - * @param string $dir The direction to sort (ASC or DESC), default ASC - * @param string $filter A string to filter the user's name by, default empty - */ - public function getUsers ($start = 0, $limit = 10, $sort = "name", $dir = "asc", $filter = "") { - - $qb = PartKeepr::getEM()->createQueryBuilder(); - $qb->select("st.id, st.username")->from("de\RaumZeitLabor\PartKeepr\User\User","st"); - - if ($filter != "") { - $qb = $qb->where("LOWER(st.username) LIKE :filter"); - $qb->setParameter("filter", "%".strtolower($filter)."%"); - } - - if ($limit > -1) { - $qb->setMaxResults($limit); - $qb->setFirstResult($start); - } - - $qb->orderBy("st.".$sort, $dir); - - $query = $qb->getQuery(); - - $result = $query->getResult(); - - $totalQueryBuilder = PartKeepr::getEM()->createQueryBuilder(); - $totalQueryBuilder->select("COUNT(st.id)")->from("de\RaumZeitLabor\PartKeepr\User\User","st"); - - - - if ($filter != "") { - $totalQueryBuilder = $totalQueryBuilder->where("LOWER(st.username) LIKE :filter"); - $totalQueryBuilder->setParameter("filter", "%".strtolower($filter)."%"); - } - - $totalQuery = $totalQueryBuilder->getQuery(); - - return array("data" => $result, "totalCount" => $totalQuery->getSingleScalarResult()); - } - - /** - * Checks if the passed user already exists. - * - * @param $username string The username to check - */ - public function userExists ($username) { - $dql = "SELECT COUNT(u) FROM de\RaumZeitLabor\PartKeepr\User\User u WHERE u.username = :name"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("name", $username); - - $count = $query->getSingleScalarResult(); - - if ($count == 0) { - return false; - } else { - return true; - } - } - - /** - * Creates the given user. Checks if the user already exists - * - * @param User $user The user to create - * @throws UserAlreadyExistsException - */ - public function createUser (User $user) { - if ($this->userExists($user->getUsername())) { - throw new UserAlreadyExistsException($user->getUsername()); - } - - PartKeepr::getEM()->persist($user); - PartKeepr::getEM()->flush(); - } - - /** - * Returns the user for a given user id - * @param integer $id The user id - */ - public function getUser ($id) { - return User::loadById($id); - } - - /** - * Deletes an user by id - * @param int $id The user's id - */ - public function deleteUser ($id) { - $user = User::loadById($id); - - PartKeepr::getEM()->remove($user); - PartKeepr::getEM()->flush(); - } - - /** - * Authenticates the given user. If successful, an instance - * of the user is returned. - * - * @param User $user The user to authenticate - * @throws InvalidLoginDataException Thrown if the user's credentials are not valid - */ - public function authenticate (User $user) { - $result = PartKeepr::getEM() - ->getRepository("de\RaumZeitLabor\PartKeepr\User\User") - ->findOneBy( - array( - "username" => $user->getUsername(), - "password" => $user->getHashedPassword() - ) - ); - - if ($result == null) { - throw new InvalidLoginDataException(); - } else { - return $result; - } - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/User/UserService.php b/src/backend/de/RaumZeitLabor/PartKeepr/User/UserService.php @@ -1,101 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\User; - -use de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Session\SessionManager; - -class UserService extends Service implements RestfulService { - - /** - * Implements the get() call for the RestfulService. - * - * If the "id" parameter is passed, try to return the user by id. If not, - * return a list. - * - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - if ($this->hasParameter("id")) { - if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { - throw new \Exception("Permission denied"); - } - - return array("data" => UserManager::getInstance()->getUser($this->getParameter("id"))->serialize()); - } else { - if ($this->hasParameter("sort")) { - $tmp = json_decode($this->getParameter("sort"), true); - - $aSortParams = $tmp[0]; - } else { - $aSortParams = array( - "property" => "username", - "direction" => "ASC"); - } - return UserManager::getInstance()->getUsers( - $this->getParameter("start", $this->getParameter("start", 0)), - $this->getParameter("limit", $this->getParameter("limit", 25)), - $this->getParameter("sortby", $aSortParams["property"]), - $this->getParameter("dir", $aSortParams["direction"]), - $this->getParameter("query", "")); - } - } - - /** - * Creates a new user. - * - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create () { - if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { - throw new \Exception("Permission denied"); - } - - $this->requireParameter("username"); - - $user = new User; - $user->deserialize($this->getParameters()); - - UserManager::getInstance()->createUser($user); - - return array("data" => $user->serialize()); - } - - /** - * Updates the user informations. - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { - throw new \Exception("Permission denied"); - } - - $this->requireParameter("id"); - $this->requireParameter("username"); - $user = UserManager::getInstance()->getUser($this->getParameter("id")); - - $user->deserialize($this->getParameters()); - PartKeepr::getEM()->flush(); - - return array("data" => $user->serialize()); - - } - - /** - * Deletes the user from the database. - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - if (!SessionManager::getCurrentSession()->getUser()->isAdmin()) { - throw new \Exception("Permission denied"); - } - - $this->requireParameter("id"); - - UserManager::getInstance()->deleteUser($this->getParameter("id")); - - return array("data" => null); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/UserPreference/Exceptions/UserPreferenceNotFoundException.php b/src/backend/de/RaumZeitLabor/PartKeepr/UserPreference/Exceptions/UserPreferenceNotFoundException.php @@ -1,20 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\UserPreference\Exceptions; - -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Is thrown when the user has given wrong credentials. - */ -class UserPreferenceNotFoundException extends SerializableException { - public function __construct (User $user, $preferenceKey) { - $message = sprintf( PartKeepr::i18n("User preference %s not found for user %s (%s)"), - $preferenceKey, - $user->getUsername(), - $user->getId()); - - parent::__construct($message); - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/UserPreference/UserPreference.php b/src/backend/de/RaumZeitLabor/PartKeepr/UserPreference/UserPreference.php @@ -1,229 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\UserPreference; - -use de\RaumZeitLabor\PartKeepr\Util\Serializable, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\Util\BaseEntity, - de\RaumZeitLabor\PartKeepr\UserPreference\Exceptions\UserPreferenceNotFoundException, - de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException, - Doctrine\ORM\NoResultException; - -/** - * Represents a user preference entry. - * - * User preferences are a simple key => value mechanism, where the developer can - * specify the key and value himself. - * - * Note that values are stored internally as serialized PHP values to keep their type. - * - * @Entity - **/ -class UserPreference implements Serializable { - /** - * Defines the key of the user preference - * @Column(type="string",length=255) - * @Id - * @var string - */ - private $preferenceKey; - - /** - * Defines the value. Note that the value is internally stored as a serialized string. - * @Column(type="text") - * @var mixed - */ - private $preferenceValue; - - /** - * Defines the user - * @ManyToOne(targetEntity="de\RaumZeitLabor\PartKeepr\User\User") - * @Id - * @var User - */ - private $user; - - - /** - * Sets the user for this entry - * @param User $user - */ - public function setUser (User $user) { - $this->user = $user; - } - - /** - * Returns the user associated with this entry - * @return \de\RaumZeitLabor\PartKeepr\User\User - */ - public function getUser () { - return $this->user; - } - - /** - * Sets the key for this user preference - * @param string $key The key name - */ - public function setKey ($key) { - $this->preferenceKey = $key; - } - - /** - * Returns the key of this entry - * @return string - */ - public function getKey () { - return $this->preferenceKey; - } - - /** - * Sets the value for this entry - * @param mixed $value - */ - public function setValue ($value) { - $this->preferenceValue = serialize($value); - } - - /** - * Returns the value for this entry - * @return mixed The value - */ - public function getValue () { - return unserialize($this->preferenceValue); - } - - /** - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Util.Serializable::serialize() - */ - public function serialize () { - return array( - "key" => $this->getKey(), - "value" => $this->getValue(), - "user_id" => $this->getUser()->getId() - ); - } - - /** - * Creates or updates a preference for a given user. - * - * @param User $user The user to set the preference for - * @param string $key The key to set - * @param string $value The value to set - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public static function setPreference (User $user, $key, $value) { - if (!PartKeepr::getEM()->contains($user)) { - throw new EntityNotPersistantException(); - } - - $dql = "SELECT up FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE up.user = :user AND "; - $dql .= "up.preferenceKey = :key"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", $user); - $query->setParameter("key", $key); - - try { - $userPreference = $query->getSingleResult(); - } catch (\Exception $e) { - $userPreference = new UserPreference(); - $userPreference->setUser($user); - $userPreference->setKey($key); - - PartKeepr::getEM()->persist($userPreference); - } - - $userPreference->setValue($value); - - PartKeepr::getEM()->flush(); - - return $userPreference; - } - - /** - * Returns a specific preference value for the given user - * - * @param User $user The user to retrieve the preference for - * @param string $key The preference key to retrieve - * @return string The preference string - * @throws UserPreferenceNotFoundException Thrown if the preference key was not found - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public static function getPreferenceValue (User $user, $key) { - $userPreference = self::getPreference($user, $key); - - return $userPreference->getValue(); - } - - /** - * Returns all preferences for the given user - * @param User $user The user - * @throws EntityNotPersistantException Thrown if the user entity is not persistent - */ - public static function getPreferences (User $user) { - if (!PartKeepr::getEM()->contains($user)) { - throw new EntityNotPersistantException(); - } - - $dql = "SELECT up FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE up.user = :user"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", $user); - - return $query->getResult(); - } - - /** - * Returns a specific preference object for the given user - * - * @param User $user The user to retrieve the preference for - * @param string $key The preference key to retrieve - * @return UserPreference The preference object - * @throws UserPreferenceNotFoundException Thrown if the preference key was not found - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public static function getPreference (User $user, $key) { - if (!PartKeepr::getEM()->contains($user)) { - throw new EntityNotPersistantException(); - } - - $dql = "SELECT up FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE up.user = :user AND "; - $dql .= "up.preferenceKey = :key"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", $user); - $query->setParameter("key", $key); - - try { - $up = $query->getSingleResult(); - return $up; - } catch (NoResultException $e) { - throw new UserPreferenceNotFoundException($user, $key); - } - } - - /** - * Removes a specific setting for a specific user. - * - * @param User $user The user to delete the preference for - * @param string $key The key to delete - * @throws EntityNotPersistantException Thrown if the entity is not persistant - */ - public static function deletePreference (User $user, $key) { - if (!PartKeepr::getEM()->contains($user)) { - throw new EntityNotPersistantException(); - } - - $dql = "DELETE FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE up.user = :user AND "; - $dql .= "up.preferenceKey = :key"; - - $query = PartKeepr::getEM()->createQuery($dql); - $query->setParameter("user", $user); - $query->setParameter("key", $key); - - $query->execute(); - } - -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/UserPreference/UserPreferenceService.php b/src/backend/de/RaumZeitLabor/PartKeepr/UserPreference/UserPreferenceService.php @@ -1,96 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\UserPreference; - -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Util\Configuration, - de\RaumZeitLabor\PartKeepr\Service\RestfulService, - de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Represents the user preference service. This service is implemented as a RestfulService, however, - * only setting and deleting properties is supported, as we don't want to have duplicate values per key. - * - * For convinience, create() and update() perform the exact same function. - * @author felicitus - * - */ -class UserPreferenceService extends Service implements RestfulService { - /** - * Returns the preferences for the current user, or a user specified by user_id (admin only). - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::get() - */ - public function get () { - $user = null; - - if ($this->hasParameter("user_id") && SessionManager::getCurrentSession()->getUser()->isAdmin()) { - if ($this->getParameter("user_id") != 0) { - $user = User::loadById($this->getParameter("user_id")); - } - } else { - $user = SessionManager::getCurrentSession()->getUser(); - } - - $aPreferences = array(); - - foreach ($user->getPreferences() as $result) { - $aPreferences[] = $result->serialize(); - } - - return array("data" => $aPreferences); - } - - /** - * Creates or updates a value for a specific key. - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::create() - */ - public function create() { - $userPreference = UserPreference::setPreference($this->getUser(), $this->getParameter("key"), $this->getParameter("value")); - - return array("data" => $userPreference->serialize()); - } - - /** - * Creates or updates a value for a specific key. - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::update() - */ - public function update () { - return $this->create(); - } - - /** - * Deletes a key-value combination from the database. - * - * (non-PHPdoc) - * @see de\RaumZeitLabor\PartKeepr\Service.RestfulService::destroy() - */ - public function destroy () { - if ($this->hasParameter("user_id") && SessionManager::getCurrentSession()->getUser()->isAdmin()) { - UserPreference::deletePreference(User::loadById($this->getParameter("user_id")), $this->getParameter("key")); - } else { - UserPreference::deletePreference($this->getUser(), $this->getParameter("key")); - } - } - - public function changePassword () { - if (Configuration::getOption("partkeepr.frontend.allow_password_change", true) === false) { - throw new \Exception("Password changing has been disabled on this server"); - } - - if (!$this->getUser()->compareHashedPassword($this->getParameter("oldpassword"))) { - throw new \Exception("Invalid Password"); - } else { - $this->getUser()->setHashedPassword($this->getParameter("newpassword")); - } - - return array("data" => PartKeepr::i18n("Password changed successfully")); - - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/BaseEntity.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/BaseEntity.php @@ -1,116 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -use de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotFoundException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** @MappedSuperclass */ -class BaseEntity { - /** - * @Id @Column(type="integer") - * @GeneratedValue(strategy="AUTO") - * @var unknown_type - */ - private $id; - - /** - * Returns the ID of this object. - * @param none - * @return int The ID of this object - */ - public function getId () { - return $this->id; - } - - /** - * Syncs a given collection with the entity's collection. - * - * This is used for 1:n or m:n relations, where we need to process inserts, updates and deletes for the records. - * - * @param array $sourceArray The array with all records which should be deserialized - * @param \Doctrine\Common\Collections\Collection $collection The collection which contains the existing records - * @param string $entityClass The class name which is used when a new entity needs to be created - */ - public function deserializeChildren (array $sourceArray, \Doctrine\Common\Collections\Collection $collection, $entityClass) { - $deletes = array(); - $inserts = array(); - - /* Round 1: Check if we've got a matching id in both lists. If yes, we know that the record - * should be updated. If no, the record should be appended */ - foreach ($sourceArray as $sourceItem) { - $bFound = false; - foreach ($collection as $item) { - if ($item->getId() == $sourceItem["id"]) { - // Directly update - $item->deserialize($sourceItem); - $bFound = true; - break; - } - } - - if (!$bFound) { - $inserts[] = $sourceItem; - } - } - - /* Round 2: Check for items which are in the collection but not in the sourceArray. */ - foreach ($collection as $targetItem) { - $bFound = false; - foreach ($sourceArray as $item) { - if ($targetItem->getId() == $item["id"]) { - $bFound = true; - break; - } - } - - if (!$bFound) { - $deletes[] = $targetItem; - } - } - - foreach ($inserts as $item) { - $class = new $entityClass; - $class->deserialize($item); - - $collection->add($class); - PartKeepr::getEM()->persist($class); - } - - /* Remove the to-be-deleted items from the collection. Note that we store the instance of the item, - * so we can simply use removeElement. - */ - foreach ($deletes as $item) { - $collection->removeElement($item); - PartKeepr::getEM()->remove($item); - } - } - - /** - * Serializes the children of a specific collection - * @param \Doctrine\Common\Collections\Collection $array The array holding BaseEntities to serialize - */ - public function serializeChildren (\Doctrine\Common\Collections\Collection $array) { - $aData = array(); - $aData["totalCount"] = $array->count(); - $aData["data"] = array(); - - foreach ($array as $item) { - $aData["data"][] = $item->serialize(); - } - - return array("response" => $aData); - } - - /** - * Loads the entity from the database. - * @param integer $id The entity's id - */ - public static function loadById ($id) { - $entity = PartKeepr::getEM()->find(get_called_class(), $id); - - if (!is_object($entity)) { - throw new EntityNotFoundException(get_called_class(), $id); - } - return $entity; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Configuration.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Configuration.php @@ -1,92 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -use de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * This class manages simple key -> value configurations within the system. - * - * This allows the user to configure certain aspects of the system in a central place. - * - * The convention is to use a dotted format, for example: - * - * flipbeat.cms.layoutrenderer - * - * @author felicitus - */ -class Configuration { - private static $options = array(); - - /** - * Sets the option to value. - * - * @param string $option The option to set - * @param string $value The value to set - */ - public static function setOption ($option, $value) { - Configuration::$options[$option] = $value; - } - - /** - * Returns the value of an option. The developer - * may additionally specify a default value, which - * is returned when no option was found. - * - * @param string $option The option to return - * @param string $default The default value if the option was not found - */ - public static function getOption ($option, $default = false) { - if (!array_key_exists($option, Configuration::$options)) { - return $default; - } - return Configuration::$options[$option]; - } - - /** - * Returns all configuration options - * - * @return array An array with key=>value assignments - */ - public static function getOptions () { - return Configuration::$options; - } - - /** - * Returns a configuration file, based on all configurations. - * - * @param none - * @return string A complete configuration file including namespace and use directives - */ - public static function dumpConfig () { - $config = <<<EOD -<?php -namespace de\RaumZeitLabor\PartKeepr; -use de\RaumZeitLabor\PartKeepr\Util\Configuration; - - -EOD; - foreach (Configuration::$options as $option => $value) { - switch (PartKeepr::getType($value)) { - case "string": - $config .= 'Configuration::setOption("'.$option.'", "'.$value.'");'."\n"; - break; - case "boolean": - $config .= 'Configuration::setOption("'.$option.'", '.($value === true ? 'true' : 'false').');'."\n"; - break; - case "integer": - case "numeric": - $config .= 'Configuration::setOption("'.$option.'", '.intval($value).');'."\n"; - break; - case "float": - $config .= 'Configuration::setOption("'.$option.'", '.floatval($value).');'."\n"; - break; - default: - break; - } - - } - - return $config; - } -} -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Deserializable.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Deserializable.php @@ -1,10 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -interface Deserializable { - /** - * Deserializes the entity from an array format - * @param $parameters array The serialized form of the entity to deserialize - */ - public function deserialize (array $parameters); -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/EntityNotFoundException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/EntityNotFoundException.php @@ -1,17 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Thrown when an entity via loadById() was not found. - */ -class EntityNotFoundException extends SerializableException { - public function __construct ($class, $id) { - parent::__construct( - sprintf( - PartKeepr::i18n("The entity %s with the id %d could not be found"), - $class, $id)); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/EntityNotPersistantException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/EntityNotPersistantException.php @@ -1,14 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException, - de\RaumZeitLabor\PartKeepr\PartKeepr; - -/** - * Thrown when an entity via loadById() was not found. - */ -class EntityNotPersistantException extends SerializableException { - public function __construct () { - parent::__construct("The entity is not persistant."); - } -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/OutOfRangeException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Exceptions/OutOfRangeException.php @@ -1,6 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util\Exceptions; - -use de\RaumZeitLabor\PartKeepr\Util\SerializableException; - -class OutOfRangeException extends SerializableException {} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/OS/OperatingSystem.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/OS/OperatingSystem.php @@ -1,94 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util\OS; - -class OperatingSystem { - /** - * Returns the platform name the system is running on. - * - * Typical return values are: "Linux", "FreeBSD", "Darwin" (Mac OSX), - * "Windows". - */ - public function getPlatform () { - if (function_exists("posix_uname")) { - $data = posix_uname(); - - if (array_key_exists("sysname", $data)) { - return $data["sysname"]; - } - } - - if (\PHP_OS == "WINNT") { - return "Windows"; - } - - return "unknown"; - } - - /** - * Returns the distribution - * @return string string - */ - public function getRelease () { - switch (strtolower($this->getPlatform())) { - case "freebsd": - /** - * Unfortunately, there's no text file on FreeBSD which tells us the release - * number. Thus, we hope that "release" within posix_uname() is defined. - */ - if (function_exists("posix_uname")) { - $data = posix_uname(); - - if (array_key_exists("release", $data)) { - return $data["release"]; - } - } - break; - case "darwin": - /** - * Mac stores its version number in a public readable plist file, which - * is in XML format. - */ - $document = new \DomDocument(); - $document->load("/System/Library/CoreServices/SystemVersion.plist"); - $xpath = new \DOMXPath($document); - $entries = $xpath->query("/plist/dict/*"); - - $previous = ""; - foreach ($entries as $entry) { - if (strpos($previous, "ProductVersion") !== false) { - return $entry->textContent; - } - $previous = $entry->textContent; - } - break; - case "linux": - return $this->getLinuxDistribution(); - break; - default: - break; - } - - return "unknown"; - } - - /** - * Tries to detect the distribution. - * - * Currently, we only execute lsb_release to find out the version number. - * As I don't have any other distributions at hand to test with, I rely - * on user feedback which distributions don't have lsb_release. - */ - public function getLinuxDistribution () { - /* Try executing lsb_release */ - $release = @exec('lsb_release -d -s', $void, $retval); - - if ($retval === 0 && $release !== "") - { - return $release; - } - - //@todo we need better handling here - return "unknown"; - } - -} diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Serializable.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Serializable.php @@ -1,11 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -interface Serializable { - /** - * Serializes the entity into an array format, which in turn can - * be used by json_encode. - * @return array The serialized form of the entity - */ - public function serialize (); -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/SerializableException.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/SerializableException.php @@ -1,59 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -class SerializableException extends \Exception { - protected $detailMessage = "No detail message has been entered."; - - /* @todo: stub */ - public function getDetail () { - return $this->detailMessage; - } - - public function setDetail ($message) { - $this->detailMessage = $message; - } - - public function serialize () { - return array( - "message" => $this->getMessage(), - "detail" => $this->getDetail(), - "exception" => get_class($this), - "code" => $this->getCode() - //"backtrace" => $this->getFormattedTrace() - ); - } - - public function getFormattedTrace () { - $items = $this->getTrace(); - - $message = ""; - - $args = array(); - - foreach ($items as $id => $item) { - foreach ($item["args"] as $item) { - switch (gettype($item)) { - case "object": - if (method_exists($item, "__toString")) { - $args[] = get_class($item) . "(".$item->__toString().")"; - } else { - $args[] = get_class($item); - } - case "array": - $args[] = "array"; - break; - default: - $args[] = $item; - break; - } - } - - $message .= $item["file"].":".$item["line"]."\n"; - $message .= $item["function"] ."(".implode(",", $args).")"."\n\n"; - } - - return $message; - } - -} -?>- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/Singleton.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/Singleton.php @@ -1,22 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -abstract class Singleton { - static $instance = null; - - private function __construct () { - - } - - /** - * Returns an instance of the current singleton - * @return $this - */ - public static function getInstance () { - if (!static::$instance instanceof static) { - static::$instance = new static; - } - - return static::$instance; - } -}- \ No newline at end of file diff --git a/src/backend/de/RaumZeitLabor/PartKeepr/Util/UtilService.php b/src/backend/de/RaumZeitLabor/PartKeepr/Util/UtilService.php @@ -1,13 +0,0 @@ -<?php -namespace de\RaumZeitLabor\PartKeepr\Util; - -use de\RaumZeitLabor\PartKeepr\Service\AnonService; - -class UtilService extends AnonService { - public function clearCache () { - apc_clear_cache(); - apc_clear_cache("user"); - - return array("status" => "ok"); - } -}- \ No newline at end of file diff --git a/src/frontend/file.php b/src/frontend/file.php @@ -1,14 +1,14 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\Footprint\FootprintAttachment, - de\RaumZeitLabor\PartKeepr\Project\ProjectAttachment, - de\RaumZeitLabor\PartKeepr\Part\PartAttachment, - de\RaumZeitLabor\PartKeepr\UploadedFile\TempUploadedFile, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Image\Image, - de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo; +namespace PartKeepr\Frontend; +use PartKeepr\Footprint\FootprintAttachment, + PartKeepr\Project\ProjectAttachment, + PartKeepr\Part\PartAttachment, + PartKeepr\UploadedFile\TempUploadedFile, + PartKeepr\PartKeepr, + PartKeepr\Image\Image, + PartKeepr\Manufacturer\ManufacturerICLogo; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(""); @@ -29,9 +29,9 @@ if (substr($id, 0, 4) === "TMP:") { case "PartKeepr.FootprintAttachment": $file = FootprintAttachment::loadById($id); break; - case "ProjectAttachment": - case "PartKeepr.ProjectAttachment": - $file = ProjectAttachment::loadById($id); + case "ProjectAttachment": + case "PartKeepr.ProjectAttachment": + $file = ProjectAttachment::loadById($id); break; default: $file = null; diff --git a/src/frontend/image.php b/src/frontend/image.php @@ -1,16 +1,20 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; +namespace PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\Part\PartImage, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationImage, - de\RaumZeitLabor\PartKeepr\Footprint\FootprintImage, - de\RaumZeitLabor\PartKeepr\TempImage\TempImage, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Image\Image, - de\RaumZeitLabor\PartKeepr\Image\CachedImage, - de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo; +use PartKeepr\Part\PartAttachment; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +use PartKeepr\Image\ImageRenderer; + +use PartKeepr\Part\PartImage, + PartKeepr\StorageLocation\StorageLocationImage, + PartKeepr\Footprint\FootprintImage, + PartKeepr\TempImage\TempImage, + PartKeepr\PartKeepr, + PartKeepr\Image\Image, + PartKeepr\Image\CachedImage, + PartKeepr\Manufacturer\ManufacturerICLogo; + +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(""); @@ -30,10 +34,12 @@ if (substr($id, 0, 4) === "TMP:") { $image = FootprintImage::loadById($id); break; case Image::IMAGE_STORAGELOCATION: - $image = StorageLocationImage::loadById($id); - break; - case Image::IMAGE_PART: - $image = PartImage::loadById($id); + $image = StorageLocationImage::loadById($id); + break; + case "partattachment": + $attachment = PartAttachment::loadById($id); + $image = new PartImage(); + $image->replace($attachment->getFilename()); break; default: $image = null; @@ -54,20 +60,7 @@ if ($image == null) { if ($image === null) { /* The image is still null - output an "image not found" image. */ - $image = imagecreate($_REQUEST["w"], $_REQUEST["h"]); - $white = imagecolorallocate($image, 255,255,255); - $black = imagecolorallocate($image, 0,0,0); - - header("Content-Type: image/png"); - - $w = $_REQUEST["w"]-1; - $h = $_REQUEST["h"]-1; - imagefill($image, 0,0, $white); - - /* Draw the X */ - imageline($image, 0,0,$w,$h, $black); - imageline($image, $w,0,0,$h, $black); - imagepng($image); + ImageRenderer::outputRenderNotFoundImage($_REQUEST["w"], $_REQUEST["h"]); exit(); } @@ -98,8 +91,7 @@ switch ($mode) { case "fit": default: $file = $image->fitWithin($_REQUEST["w"],$_REQUEST["h"]); - break; - + break; } diff --git a/src/frontend/index.php b/src/frontend/index.php @@ -1,13 +1,13 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; +namespace PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\Service\ServiceManager, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Session\SessionManager, - de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\User\User, + PartKeepr\Service\ServiceManager, + PartKeepr\PartKeepr, + PartKeepr\Session\SessionManager, + PartKeepr\Util\Configuration; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); include_once 'Twig/Autoloader.php'; PartKeepr::initialize(""); @@ -45,8 +45,8 @@ if (Configuration::getOption("partkeepr.auth.http", false) === true) { $aPreferences = array(); - foreach ($user->getPreferences() as $result) { - $aPreferences[] = $result->serialize(); + foreach ($user->getPreferences() as $result) { + $aPreferences[] = $result->serialize(); } $aParameters["userPreferences"] = array("response" => array("data" => $aPreferences)); diff --git a/src/frontend/js/Components/Part/Editor/PartDistributorGrid.js b/src/frontend/js/Components/Part/Editor/PartDistributorGrid.js @@ -52,7 +52,7 @@ Ext.define('PartKeepr.PartDistributorGrid', { }, { header : i18n("Order Number"), dataIndex : 'orderNumber', - flex : 0.3, + flex : 0.2, editor : { xtype : 'textfield', allowBlank : true @@ -78,6 +78,14 @@ Ext.define('PartKeepr.PartDistributorGrid', { xtype : 'CurrencyField', allowBlank : false } + }, { + header : i18n("SKU"), + dataIndex : 'sku', + flex : 0.1, + editor : { + xtype : 'textfield', + allowBlank : true + } } ]; this.callParent(); @@ -116,4 +124,4 @@ Ext.define('PartKeepr.PartDistributorGrid', { onSelectChange : function(selModel, selections) { this.deleteButton.setDisabled(selections.length === 0); } -});- \ No newline at end of file +}); diff --git a/src/frontend/js/Components/Part/PartDisplay.js b/src/frontend/js/Components/Part/PartDisplay.js @@ -6,6 +6,8 @@ Ext.define('PartKeepr.PartDisplay', { extend: 'Ext.panel.Panel', bodyCls: 'partdisplay', + autoScroll: true, + /** * Initializes the component and adds a template as well as the add/remove stock and edit part buttons. */ @@ -55,7 +57,7 @@ Ext.define('PartKeepr.PartDisplay', { '</tr>', '<tr>', '<td class="e">'+i18n("Used in projects")+':</td>', - '<td class="e">{projects}</td>', + '<td class="e">{[ (values.projects == "") ? "'+i18n("none")+'" : values.projects ]}</td>', '</tr>', '</table>'); @@ -105,6 +107,10 @@ Ext.define('PartKeepr.PartDisplay', { */ this.addEvents("editPart"); + this.imageDisplay = Ext.create("PartKeepr.PartImageDisplay"); + this.infoContainer = Ext.create("Ext.container.Container"); + + this.items = [ this.infoContainer, this.imageDisplay ]; this.callParent(); }, /** @@ -125,7 +131,13 @@ Ext.define('PartKeepr.PartDisplay', { } } - this.tpl.overwrite(this.getTargetEl(), values); + this.tpl.overwrite(this.infoContainer.getEl(), values); + this.imageDisplay.setStore(this.record.attachments()); + + this.doLayout(); + // Scroll the container to top in case the user scrolled the part, then switched to another part + this.getTargetEl().scrollTo("top", 0); + }, /** * Prompt the user for the stock level he wishes to add. @@ -137,12 +149,13 @@ Ext.define('PartKeepr.PartDisplay', { /** * Callback after the "add stock" dialog is complete. */ - addPartHandler: function (quantity, price) { + addPartHandler: function (quantity, price, comment) { var call = new PartKeepr.ServiceCall( "Part", "addStock"); call.setParameter("stock", quantity); call.setParameter("price", price); + call.setParameter("comment", comment); call.setParameter("part", this.record.get("id")); call.setHandler(Ext.bind(this.reloadPart, this)); call.doCall(); @@ -189,4 +202,4 @@ Ext.define('PartKeepr.PartDisplay', { this.setValues(this.record); this.record.commit(); } -});- \ No newline at end of file +}); diff --git a/src/frontend/js/Components/Part/PartImageDisplay.js b/src/frontend/js/Components/Part/PartImageDisplay.js @@ -0,0 +1,143 @@ +/** + * @class PartKeepr.PartImageDisplay + * Provides a display of all part images with scroll-through functionality. + */ +Ext.define('PartKeepr.PartImageDisplay', { + extend: 'Ext.panel.Panel', + + displayedImageId: 0, + maxImageWidth: 200, + maxImageHeight: 150, + + layout: 'hbox', + border: false, + + /** + * Initializes the component and creates all widgets. + */ + initComponent: function () { + this.prevButton = Ext.create("Ext.button.Button", { + text: '<', + width: 20, + height: this.maxImageHeight, + handler: this.onPreviousClick, + scope: this + }); + + this.nextButton = Ext.create("Ext.button.Button", { + text: '>', + width: 20, + height: this.maxImageHeight, + handler: this.onNextClick, + scope: this + }); + + this.imageDisplay = Ext.create("Ext.container.Container", { + height: this.maxImageHeight, + width: this.maxImageWidth, + style: 'align: center' + }); + + this.items = [ this.prevButton, this.imageDisplay, this.nextButton ]; + + this.tpl = new Ext.XTemplate('<img src="{image}"/>'); + + this.callParent(); + }, + /** + * Sets the stored when a new part is selected. + * @param store The store + */ + setStore: function (store) { + var imageSet = false; + + this.store = store; + + this.displayedImageId = 0; + + var id = this.getImageToDisplayForward(0); + + if (id !== -1) { + this.setImage(id); + imageSet = true; + + } + + if (!imageSet) { + this.tpl.overwrite(this.imageDisplay.getEl(), { image: 'image.php?type=partattachment&id=0&w='+this.maxImageWidth+'&h='+this.maxImageHeight}); + } + }, + /** + * Sets the image + * @param id The attachment ID to set + */ + setImage: function (id) { + this.tpl.overwrite(this.imageDisplay.getEl(), { image: 'image.php?type=partattachment&m=fitexact&w='+this.maxImageWidth+'&h='+this.maxImageHeight+'&id='+id}); + this.displayedImageId = id; + }, + /** + * Handler for the "next" button + */ + onNextClick: function () { + var imgId = this.getImageToDisplayForward(this.displayedImageId); + + if (imgId !== -1) { + this.setImage(imgId); + } + }, + /** + * Handler for the "previous" button + */ + onPreviousClick: function () { + var imgId = this.getImageToDisplayBackward(this.displayedImageId); + + if (imgId !== -1) { + this.setImage(imgId); + } + + }, + /** + * Returns the next image in the attachment store + * @param startId The start ID + * @returns int An attachment id, or -1 of none was found + */ + getImageToDisplayForward: function (startId) { + var startIdx = this.store.findExact("id", startId); + + if (startIdx === -1) { + startIdx = 0; + } else { + startIdx++; + } + + for (var i=startIdx;i<this.store.count();i++) { + if (this.store.getAt(i).get("image")) { + return this.store.getAt(i).get("id"); + } + } + + return -1; + }, + /** + * Returns the previous image in the attachment store + * @param startId The start ID + * @returns int An attachment id, or -1 of none was found + */ + getImageToDisplayBackward: function (startId) { + var startIdx = this.store.findExact("id", startId); + + if (startIdx >= this.store.count()) { + startIdx = this.store.count()-1; + } else { + startIdx--; + } + + for (var i=startIdx;i>-1;i--) { + if (this.store.getAt(i).get("image")) { + return this.store.getAt(i).get("id"); + } + } + + return -1; + } +});+ \ No newline at end of file diff --git a/src/frontend/js/Components/Part/PartStockWindow.js b/src/frontend/js/Components/Part/PartStockWindow.js @@ -8,7 +8,7 @@ Ext.define('PartKeepr.PartStockWindow', { // Configurations constrainHeader : true, width : 305, - height : 155, + height : 180, resizable : false, @@ -68,6 +68,23 @@ Ext.define('PartKeepr.PartStockWindow', { checked : true }); + this.commentField = Ext.create("Ext.form.field.Text", { + anchor : '100%', + fieldLabel : i18n("Comment"), + maxLength : 255, + enforceMaxLength : true, + listeners : { + specialkey : { + fn : function(field, e) { + if (e.getKey() == e.ENTER) { + this.onOKClick(); + } + }, + scope : this + } + } + }); + this.form = Ext.create("Ext.form.Panel", { bodyStyle : 'background:#DBDBDB;', border : false, @@ -81,7 +98,7 @@ Ext.define('PartKeepr.PartStockWindow', { margin : "0 0 0 5", value : this.partUnitName } ] - }, this.priceField, this.priceCheckbox ] + }, this.priceField, this.priceCheckbox, this.commentField ] }); this.items = this.form; @@ -126,13 +143,13 @@ Ext.define('PartKeepr.PartStockWindow', { Ext.callback( this.callbackFn, this.callbackScope, - [ this.quantityField.getValue(), price ]); + [ this.quantityField.getValue(), price, this.commentField.getValue() ]); this.close(); } }, /** - * Opens the window in "add stock" mode. The target callback receives two parameters: the value of the quantity - * field and the value of the price field. + * Opens the window in "add stock" mode. The target callback receives three parameters: the value of the quantity + * field, the value of the price field and the value of the comment field. * * @param fn * The callback @@ -161,8 +178,9 @@ Ext.define('PartKeepr.PartStockWindow', { this.setTitle(this.removePartText); this.priceField.hide(); this.priceCheckbox.hide(); + this.commentField.hide(); this.setHeight(105); this.okButton.setIcon("resources/silkicons/brick_delete.png"); this.show(); } -});- \ No newline at end of file +}); diff --git a/src/frontend/js/Models/PartAttachment.js b/src/frontend/js/Models/PartAttachment.js @@ -5,6 +5,7 @@ Ext.define("PartKeepr.PartAttachment", { { name: 'originalFilename', type: 'string' }, { name: 'footprint_id', type: 'int' }, { name: 'mimetype', type: 'string' }, + { name: 'image', type: 'boolean' }, { name: 'extension', type: 'string' }, { name: 'description', type: 'string' }, { name: 'size', type: 'string' } diff --git a/src/frontend/js/Models/PartDistributor.js b/src/frontend/js/Models/PartDistributor.js @@ -1,16 +1,17 @@ Ext.define("PartKeepr.PartDistributor", { extend: "Ext.data.Model", fields: [ - { id: 'id', name: 'id', type: 'int' }, - { name: 'part_id', type: 'int' }, - { name: 'part_name', type: 'string' }, - { name: 'distributor_id', type: 'int' }, - { name: 'distributor_name', type: 'string' }, - { name: 'price', type: 'float' }, - { name: 'orderNumber', type: 'string' }, - { name: 'packagingUnit', type: 'int'} + { id: 'id', name: 'id', type: 'int' }, + { name: 'part_id', type: 'int' }, + { name: 'part_name', type: 'string' }, + { name: 'distributor_id', type: 'int' }, + { name: 'distributor_name', type: 'string' }, + { name: 'price', type: 'float' }, + { name: 'orderNumber', type: 'string' }, + { name: 'packagingUnit', type: 'int'}, + { name: 'sku', type: 'string' } ], belongsTo: { type: 'belongsTo', model: 'PartKeepr.Part', primaryKey: 'id', foreignKey: 'part_id'}, belongsTo: { type: 'belongsTo', model: 'PartKeepr.Distributor', primaryKey: 'id', foreignKey: 'distributor_id'}, proxy: PartKeepr.getRESTProxy("PartDistributor") -});- \ No newline at end of file +}); diff --git a/src/frontend/js/Util/i18n.js b/src/frontend/js/Util/i18n.js @@ -1,3 +1,8 @@ +/** + * Returns an internationalized string. + * @param string + * @return {*} + */ function i18n (string) { return string; } \ No newline at end of file diff --git a/src/frontend/rest.php b/src/frontend/rest.php @@ -1,10 +1,10 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; +namespace PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Service\ServiceManager; +use PartKeepr\PartKeepr, + PartKeepr\Service\ServiceManager; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(""); @@ -39,7 +39,7 @@ $timingStart = microtime(true); * rest.php/Part * * /Part specifies that you wish to call the Part service. The service manager automatically extends the short "Part" - * name to the class de\RaumZeitLabor\PartKeepr\Part\PartService. + * name to the class PartKeepr\Part\PartService. * * REST * ==== @@ -57,7 +57,7 @@ try { echo json_encode($response); -} catch (\de\RaumZeitLabor\PartKeepr\Util\SerializableException $e) { +} catch (\PartKeepr\Util\SerializableException $e) { header('HTTP/1.0 400 Exception', false, 400); $response = array(); $response["status"] = "error"; diff --git a/src/frontend/rss.php b/src/frontend/rss.php @@ -1,10 +1,10 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; +namespace PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\PartKeepr, + PartKeepr\Util\Configuration; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); header("Content-Type: text/xml; charset=UTF-8"); diff --git a/src/frontend/service.php b/src/frontend/service.php @@ -1,10 +1,10 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; +namespace PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\Service\ServiceManager; -use de\RaumZeitLabor\PartKeepr\PartKeepr; +use PartKeepr\Service\ServiceManager; +use PartKeepr\PartKeepr; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(""); @@ -27,7 +27,7 @@ try { $response["response"] = ServiceManager::call($request); $response["timing"] = microtime(true) - $timingStart; -} catch (de\RaumZeitLabor\PartKeepr\Util\SerializableException $e) { +} catch (PartKeepr\Util\SerializableException $e) { $response = array(); $response["status"] = "error"; $response["exception"] = $e->serialize(); diff --git a/src/frontend/upload.php b/src/frontend/upload.php @@ -1,12 +1,12 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Frontend; +namespace PartKeepr\Frontend; -use de\RaumZeitLabor\PartKeepr\PartKeepr; -use de\RaumZeitLabor\PartKeepr\Image\Image; -use de\RaumZeitLabor\PartKeepr\Manufacturer\ManufacturerICLogo; -use de\RaumZeitLabor\PartKeepr\Manufacturer\Manufacturer; +use PartKeepr\PartKeepr; +use PartKeepr\Image\Image; +use PartKeepr\Manufacturer\ManufacturerICLogo; +use PartKeepr\Manufacturer\Manufacturer; -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(""); diff --git a/src/setup/setup.php b/src/setup/setup.php @@ -1,26 +1,26 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Setup; +namespace PartKeepr\Setup; -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Setup\Setup, - de\RaumZeitLabor\PartKeepr\Util\SerializableException; +use PartKeepr\PartKeepr, + PartKeepr\Setup\Setup, + PartKeepr\Util\SerializableException; -set_error_handler(create_function('$a, $b, $c, $d', 'throw new ErrorException($b, 0, $a, $c, $d);'), E_ALL); +set_error_handler(create_function('$a, $b, $c, $d', 'throw new ErrorException($b, 0, $a, $c, $d);'), E_ALL); -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initializeClassLoaders(); -try { - Setup::setDatabaseConfigurationFromRequest(); -} catch (\Exception $e) { - echo json_encode(array("error" => true, "message" => $e->getMessage())); - exit; +try { + Setup::setDatabaseConfigurationFromRequest(); +} catch (\Exception $e) { + echo json_encode(array("error" => true, "message" => $e->getMessage())); + exit; } PartKeepr::initializeDoctrine(); -$setup = new Setup(); +$setup = new Setup(); try { /** diff --git a/src/setup/tests/check-database-connectivity.php b/src/setup/tests/check-database-connectivity.php @@ -2,16 +2,16 @@ /** * Tests the connection to the database. */ -include("../../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../../src/backend/PartKeepr/PartKeepr.php"); use Doctrine\Common\ClassLoader; -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Setup\Setup, - de\RaumZeitLabor\PartKeepr\Setup\SchemaSetup; +use PartKeepr\PartKeepr, + PartKeepr\Setup\Setup, + PartKeepr\Setup\SchemaSetup; PartKeepr::initializeClassLoaders(); -$config = new \Doctrine\DBAL\Configuration(); +$config = new \Doctrine\DBAL\Configuration(); /** * Test if the requested driver is available @@ -22,7 +22,7 @@ $drivers = PDO::getAvailableDrivers(); $bDriverAvailable = false; if (!in_array($_REQUEST["driver"], $drivers)) { - echo json_encode(array("error" => true, "message" => "The requested driver isn't installed as PHP pdo module. Please install the PDO driver for PHP.")); + echo json_encode(array("error" => true, "message" => "The requested driver isn't installed as PHP pdo module. Please install the PDO driver for PHP.")); exit; } @@ -33,7 +33,7 @@ try { $onnectionOptions = Setup::setDatabaseConfigurationFromRequest(); $connectionOptions = PartKeepr::createConnectionOptionsFromConfig(); } catch (\Exception $e) { - echo json_encode(array("error" => true, "message" => $e->getMessage())); + echo json_encode(array("error" => true, "message" => $e->getMessage())); exit; } @@ -60,12 +60,12 @@ switch ($_REQUEST["driver"]) { function performAdditionalMySQLTests ($connection, $dbname) { if (!SchemaSetup::mysqlHasUTF8Encoding($connection, $dbname)) { - echo json_encode(array("error" => true, "message" => "Your database doesn't have the proper encoding. Please change it using the following SQL statement: <br/><br/><code>ALTER DATABASE ".$dbname." CHARACTER SET utf8;</code>")); + echo json_encode(array("error" => true, "message" => "Your database doesn't have the proper encoding. Please change it using the following SQL statement: <br/><br/><code>ALTER DATABASE ".$dbname." CHARACTER SET utf8;</code>")); exit; } } -echo json_encode(array("error" => false)); +echo json_encode(array("error" => false)); /** * Returns error messages for a specific platform and PDOException code @@ -89,15 +89,15 @@ function getPlatformSpecificErrorMessage($platform, $code) { * @return An error message, or "" if no message is available. */ function getMySQLSpecificErrorMessage ($code) { - switch ($code) { - case 1044: - return "<br/><br/>You need to grant permissions to the database, or you haven't created the database yet."; - break; - case 1045: - return "<br/><br/>It seems that you have mistyped your username or password."; - break; - case 2013: - return "<br/><br/>This error is an indication that the database host you have specified is not reachable, or that your database runs on a different port."; + switch ($code) { + case 1044: + return "<br/><br/>You need to grant permissions to the database, or you haven't created the database yet."; + break; + case 1045: + return "<br/><br/>It seems that you have mistyped your username or password."; + break; + case 2013: + return "<br/><br/>This error is an indication that the database host you have specified is not reachable, or that your database runs on a different port."; break; default: return ""; diff --git a/testing/PartTest.php b/testing/PartTest.php @@ -2,7 +2,7 @@ namespace de\RaumZeitLabor\PartKeepr\Tests; declare(encoding = 'UTF-8'); -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); use de\RaumZeitLabor\PartKeepr\Auth\User; use de\RaumZeitLabor\PartKeepr\Footprint\Footprint; @@ -12,8 +12,33 @@ use de\RaumZeitLabor\PartKeepr\Category\CategoryManager; use de\RaumZeitLabor\PartKeepr\PartKeepr; use de\RaumZeitLabor\PartKeepr\Part\Part; use de\RaumZeitLabor\PartKeepr\Part\PartAttachment; +use de\RaumZeitLabor\PartKeepr\PartUnit\PartUnitManager; +use Doctrine\DBAL\Migrations\Migration, + Doctrine\DBAL\Migrations\Configuration\YamlConfiguration; PartKeepr::initialize(); -$test = new PartAttachment(); -$test->replaceFromURL("http://www.datasheetcatalog.org/datasheet/motorola/MCT7809BD2T.pdf"); + +$aPartResults[] = array(); + +$dql = "SELECT pp.quantity, p.id FROM "; +$dql .= "de\RaumZeitLabor\PartKeepr\Project\ProjectPart pp JOIN pp.part p WHERE pp.project = :project"; + +$query = PartKeepr::getEM()->createQuery($dql); +$query->setParameter("project", 1); + +foreach ($query->getArrayResult() as $result) { + $part = Part::loadById($result["id"]); + + if (array_key_exists($result["id"], $aPartResults)) { + $aPartResults[$result["id"]]["quantity"] += $result["quantity"]; + } else { + $aPartResults[$result["id"]] = array( + "quantity" => $result["quantity"], + "part" => array("response" => array("totalCount" => 1, "data" => $part->serialize())), + "storageLocation_name" => $part->getStorageLocation()->getName() + ); + } +} + +print_r($aPartResults);+ \ No newline at end of file diff --git a/testing/Service.php b/testing/Service.php @@ -2,7 +2,7 @@ namespace de\RaumZeitLabor\PartKeepr\Tests; declare(encoding = 'UTF-8'); -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); use de\RaumZeitLabor\PartKeepr\Auth\User; use de\RaumZeitLabor\PartKeepr\PartKeepr; diff --git a/testing/SetupDatabase.php b/testing/SetupDatabase.php @@ -1,19 +1,19 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests; +namespace PartKeepr\Testing; declare(encoding = 'UTF-8'); -use de\RaumZeitLabor\PartKeepr\PartKeepr; -use de\RaumZeitLabor\PartKeepr\Setup\Migration\PartDB\PartDBMigration; -use de\RaumZeitLabor\PartKeepr\Util\Configuration; -use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager; +use PartKeepr\PartKeepr, + PartKeepr\Setup\Migration\PartDB\PartDBMigration, + PartKeepr\Util\Configuration, + PartKeepr\PartCategory\PartCategoryManager; -use de\RaumZeitLabor\PartKeepr\Setup\Setup; +use PartKeepr\Setup\Setup; declare(encoding = 'UTF-8'); -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); PartKeepr::initialize(); @@ -76,15 +76,15 @@ $setup->run(); if ($migration) { - if (Configuration::getOption("partkeepr.migration.partdb.hostname", false) === false || - Configuration::getOption("partkeepr.migration.partdb.username", false) === false || - Configuration::getOption("partkeepr.migration.partdb.password", false) === false || - Configuration::getOption("partkeepr.migration.partdb.dbname", false) === false) { - - echo "Error migrating from partdb: One or more configuration settings are missing.\n"; + if (Configuration::getOption("partkeepr.migration.partdb.hostname", false) === false || + Configuration::getOption("partkeepr.migration.partdb.username", false) === false || + Configuration::getOption("partkeepr.migration.partdb.password", false) === false || + Configuration::getOption("partkeepr.migration.partdb.dbname", false) === false) { + + echo "Error migrating from partdb: One or more configuration settings are missing.\n"; echo "Please make sure that you define the partkeepr.migration.partdb.* keys, as shown in config.php.template\n\n"; - echo "After adjusting the keys, you can safely re-run the setup, even if you already have worked with PartKeepr.\n"; - exit; + echo "After adjusting the keys, you can safely re-run the setup, even if you already have worked with PartKeepr.\n"; + exit; } mysql_connect(Configuration::getOption("partkeepr.migration.partdb.hostname"), Configuration::getOption("partkeepr.migration.partdb.username"), Configuration::getOption("partkeepr.migration.partdb.password")); mysql_query("SET CHARACTER SET UTF8"); diff --git a/testing/genman.php b/testing/genman.php @@ -1,5 +1,5 @@ <?php -include("../src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include("../src/backend/PartKeepr/PartKeepr.php"); use de\RaumZeitLabor\PartKeepr\PartKeepr; diff --git a/tests/Auth/UserTest.php b/tests/Auth/UserTest.php @@ -1,7 +1,7 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\Auth; +namespace PartKeepr\Tests\Auth; -use de\RaumZeitLabor\PartKeepr\User\User; +use PartKeepr\User\User; class UserTest extends \PHPUnit_Framework_TestCase { public function testBasics () { diff --git a/tests/Logger/LoggerTest.php b/tests/Logger/LoggerTest.php @@ -1,8 +1,8 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\Logger; +namespace PartKeepr\Tests\Logger; -use de\RaumZeitLabor\PartKeepr\Logger\Logger, - de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\Logger\Logger, + PartKeepr\Util\Configuration; class LoggerTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/Part/PartServiceTest.php b/tests/Part/PartServiceTest.php @@ -1,14 +1,14 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\Part; +namespace PartKeepr\Tests\Part; -use de\RaumZeitLabor\PartKeepr\Distributor\DistributorService; +use PartKeepr\Distributor\DistributorService; -use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\Part\PartService, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\Part, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationManager, - de\RaumZeitLabor\PartKeepr\StorageLocation\StorageLocationService; +use PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\Part\PartService, + PartKeepr\PartKeepr, + PartKeepr\Part\Part, + PartKeepr\StorageLocation\StorageLocationManager, + PartKeepr\StorageLocation\StorageLocationService; class PartServiceTest extends \PHPUnit_Framework_TestCase { protected $backupGlobals = false; @@ -26,7 +26,7 @@ class PartServiceTest extends \PHPUnit_Framework_TestCase { } /** - * @expectedException de\RaumZeitLabor\PartKeepr\Part\Exceptions\CategoryNotAssignedException + * @expectedException PartKeepr\Part\Exceptions\CategoryNotAssignedException */ public function testCreatePartWithoutCategory () { $partName = "testCreatePartWithoutCategory"; @@ -98,19 +98,19 @@ class PartServiceTest extends \PHPUnit_Framework_TestCase { $service->create(); } - /** - * @expectedException de\RaumZeitLabor\PartKeepr\Part\Exceptions\StorageLocationNotAssignedException - */ - public function testCreatePartWithoutStorageLocation () { - $partName = "testCreatePartWithoutStorageLocation"; - - $part = array( + /** + * @expectedException PartKeepr\Part\Exceptions\StorageLocationNotAssignedException + */ + public function testCreatePartWithoutStorageLocation () { + $partName = "testCreatePartWithoutStorageLocation"; + + $part = array( "name" => $partName, - "category" => 1 - ); - - $service = new PartService($part); - $service->create(); + "category" => 1 + ); + + $service = new PartService($part); + $service->create(); } /** diff --git a/tests/Service/ServiceTest.php b/tests/Service/ServiceTest.php @@ -1,9 +1,9 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\Service; +namespace PartKeepr\Tests\Service; -use de\RaumZeitLabor\PartKeepr\Service\Service, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\Part\Part; +use PartKeepr\Service\Service, + PartKeepr\PartKeepr, + PartKeepr\Part\Part; class ServiceTest extends \PHPUnit_Framework_TestCase { diff --git a/tests/User/UserTest.php b/tests/User/UserTest.php @@ -1,9 +1,9 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\User; +namespace PartKeepr\Tests\User; -use de\RaumZeitLabor\PartKeepr\User\UserManager, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User; +use PartKeepr\User\UserManager, + PartKeepr\PartKeepr, + PartKeepr\User\User; class UserTest extends \PHPUnit_Framework_TestCase { protected $backupGlobals = false; @@ -99,7 +99,7 @@ class UserTest extends \PHPUnit_Framework_TestCase { /** * Makes sure that an exception is thrown when attempting to set a preference if the user is not persistant yet. * - * @expectedException de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException + * @expectedException PartKeepr\Util\Exceptions\EntityNotPersistantException */ public function testSetNonPersistantUserPreference () { $user = new User(); @@ -109,7 +109,7 @@ class UserTest extends \PHPUnit_Framework_TestCase { /** * Makes sure that an exception is thrown when attempting to get a preference if the user is not persistant yet. * - * @expectedException de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException + * @expectedException PartKeepr\Util\Exceptions\EntityNotPersistantException */ public function testGetNonPersistantUserPreference () { $user = new User(); @@ -119,7 +119,7 @@ class UserTest extends \PHPUnit_Framework_TestCase { /** * Makes sure that an exception is thrown when attempting to delete a preference if the user is not persistant yet. * - * @expectedException de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException + * @expectedException PartKeepr\Util\Exceptions\EntityNotPersistantException */ public function testDeleteNonPersistantUserPreference () { $user = new User(); diff --git a/tests/UserPreference/UserPreferenceTest.php b/tests/UserPreference/UserPreferenceTest.php @@ -1,9 +1,9 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\UserPreference; +namespace PartKeepr\Tests\UserPreference; -use de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User, - de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference; +use PartKeepr\PartKeepr, + PartKeepr\User\User, + PartKeepr\UserPreference\UserPreference; class UserPreferenceTest extends \PHPUnit_Framework_TestCase { protected $user; @@ -35,7 +35,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { * @return nothing */ protected function deleteUserPreferences () { - $dql = "DELETE FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE up.user = :user"; + $dql = "DELETE FROM PartKeepr\UserPreference\UserPreference up WHERE up.user = :user"; $query = PartKeepr::getEM()->createQuery($dql); $query->setParameter("user", $this->user); @@ -63,7 +63,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { // Make sure that we only get one result when we set the same preference twice UserPreference::setPreference($this->user, $preferenceKey, $preferenceValue); - $dql = "SELECT COUNT(up) FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE "; + $dql = "SELECT COUNT(up) FROM PartKeepr\UserPreference\UserPreference up WHERE "; $dql .= "up.user = :user AND up.preferenceKey = :key"; $query = PartKeepr::getEM()->createQuery($dql); @@ -75,7 +75,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { /** * Tests if the correct exception is thrown when attempting to load a non-existing user preference - * @expectedException de\RaumZeitLabor\PartKeepr\UserPreference\Exceptions\UserPreferenceNotFoundException + * @expectedException PartKeepr\UserPreference\Exceptions\UserPreferenceNotFoundException */ public function testGetNonExistingUserPreference () { $preferenceKey = "test2"; @@ -89,7 +89,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { * We're expecting the UserPreferenceNotFoundException because we are attempting to retrieve the value of the * previously deleted value. * - * @expectedException de\RaumZeitLabor\PartKeepr\UserPreference\Exceptions\UserPreferenceNotFoundException + * @expectedException PartKeepr\UserPreference\Exceptions\UserPreferenceNotFoundException */ public function testDeleteUserPreference () { $preferenceKey = "test3"; @@ -114,7 +114,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { UserPreference::setPreference($this->user, $preferenceKey, $preferenceValue); - $dql = "SELECT up.preferenceValue FROM de\RaumZeitLabor\PartKeepr\UserPreference\UserPreference up WHERE "; + $dql = "SELECT up.preferenceValue FROM PartKeepr\UserPreference\UserPreference up WHERE "; $dql .= "up.user = :user AND up.preferenceKey = :key"; $query = PartKeepr::getEM()->createQuery($dql); @@ -146,7 +146,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { /** * Makes sure that an exception is thrown when attempting to set a preference if the user is not persistant yet. * - * @expectedException de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException + * @expectedException PartKeepr\Util\Exceptions\EntityNotPersistantException */ public function testSetNonPersistantUserPreference () { $user = new User(); @@ -156,7 +156,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { /** * Makes sure that an exception is thrown when attempting to get a preference if the user is not persistant yet. * - * @expectedException de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException + * @expectedException PartKeepr\Util\Exceptions\EntityNotPersistantException */ public function testGetNonPersistantUserPreference () { $user = new User(); @@ -166,7 +166,7 @@ class UserPreferenceTest extends \PHPUnit_Framework_TestCase { /** * Makes sure that an exception is thrown when attempting to delete a preference if the user is not persistant yet. * - * @expectedException de\RaumZeitLabor\PartKeepr\Util\Exceptions\EntityNotPersistantException + * @expectedException PartKeepr\Util\Exceptions\EntityNotPersistantException */ public function testDeleteNonPersistantUserPreference () { $user = new User(); diff --git a/tests/Util/ConfigurationTest.php b/tests/Util/ConfigurationTest.php @@ -1,7 +1,7 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests\Util; +namespace PartKeepr\Tests\Util; -use de\RaumZeitLabor\PartKeepr\Util\Configuration; +use PartKeepr\Util\Configuration; class ConfigurationTest extends \PHPUnit_Framework_TestCase { public function testConfiguration () { diff --git a/tests/bootstrap.php b/tests/bootstrap.php @@ -1,11 +1,11 @@ <?php -namespace de\RaumZeitLabor\PartKeepr\Tests; +namespace PartKeepr\Tests; -use de\RaumZeitLabor\PartKeepr\PartCategory\PartCategoryManager, - de\RaumZeitLabor\PartKeepr\PartKeepr, - de\RaumZeitLabor\PartKeepr\User\User; +use PartKeepr\PartCategory\PartCategoryManager, + PartKeepr\PartKeepr, + PartKeepr\User\User; -include(dirname(__DIR__). "/src/backend/de/RaumZeitLabor/PartKeepr/PartKeepr.php"); +include(dirname(__DIR__). "/src/backend/PartKeepr/PartKeepr.php"); /** * Initializes a bootstrapped PartKeepr environment. diff --git a/util/classes/ExtJSFile.php b/util/classes/ExtJSFile.php @@ -37,6 +37,8 @@ class ExtJSFile { * @param string $file The source file */ public function __construct ($file) { + $file = str_replace("//", "/", $file); + $this->source = file_get_contents($file); if ($this->parseExtendDirective() != "") {