From d950880d654667f2d44c5f24b7f3f57ea4b82afa Mon Sep 17 00:00:00 2001 From: Raphael Martin Date: Tue, 5 Dec 2023 10:40:47 +0100 Subject: [PATCH] inital commit --- Classes/Controller/IngredientsController.php | 114 +++ Classes/Controller/ProductsController.php | 222 ++++++ Classes/Domain/Model/Brands.php | 104 +++ Classes/Domain/Model/Categories.php | 180 +++++ Classes/Domain/Model/FilterOptions.php | 120 ++++ Classes/Domain/Model/FilterValues.php | 99 +++ Classes/Domain/Model/Filters.php | 234 ++++++ Classes/Domain/Model/Ingredients.php | 303 ++++++++ Classes/Domain/Model/MasonryItem.php | 96 +++ Classes/Domain/Model/ProductVariantSizes.php | 180 +++++ Classes/Domain/Model/ProductVariants.php | 632 ++++++++++++++++ Classes/Domain/Model/Products.php | 677 ++++++++++++++++++ Classes/Domain/Model/SelectableAttribute.php | 87 +++ .../Repository/CategoriesRepository.php | 43 ++ .../Repository/FilterOptionsRepository.php | 30 + .../Domain/Repository/FiltersRepository.php | 51 ++ .../Repository/IngredientsRepository.php | 33 + .../Repository/ProductVariantsRepository.php | 27 + .../Domain/Repository/ProductsRepository.php | 204 ++++++ .../InjectCategoriesRepositoryTrait.php | 32 + .../InjectContentObjectRendererTrait.php | 33 + .../InjectFilterOptionsRepositoryTrait.php | 35 + .../Traits/InjectFiltersRepositoryTrait.php | 31 + .../Domain/Traits/InjectImageServiceTrait.php | 35 + .../InjectIngredientsRepositoryTrait.php | 27 + .../Traits/InjectProductsRepositoryTrait.php | 32 + .../EventListener/ProductsHrefLang.php | 51 ++ Classes/PageTitle/A2gPageTitleProvider.php | 22 + Classes/Services/FeuserSessionService.php | 79 ++ Classes/User/FilterValuesMatcher.php | 127 ++++ Classes/User/Tca.php | 21 + Classes/User/TypoScript.php | 41 ++ Classes/Utility/CanonicalUtility.php | 68 ++ .../ViewHelpers/FilterActiveViewHelper.php | 58 ++ Configuration/.htaccess | 2 + Configuration/Extbase/Persistence/Classes.php | 20 + Configuration/FlexForms/flexform_detail.xml | 104 +++ .../FlexForms/flexform_ingredients_detail.xml | 64 ++ .../FlexForms/flexform_ingredients_list.xml | 34 + Configuration/FlexForms/flexform_list.xml | 104 +++ Configuration/Services.yml | 21 + .../TCA/Overrides/100_sys_template.php | 30 + .../TCA/Overrides/102_tt_content.php | 60 ++ Configuration/TCA/Overrides/500_cropping.php | 61 ++ .../tx_a2gproducts_domain_model_brands.php | 164 +++++ ...tx_a2gproducts_domain_model_categories.php | 199 +++++ ...a2gproducts_domain_model_filteroptions.php | 102 +++ .../tx_a2gproducts_domain_model_filters.php | 180 +++++ ..._a2gproducts_domain_model_filtervalues.php | 117 +++ ...x_a2gproducts_domain_model_ingredients.php | 308 ++++++++ .../tx_a2gproducts_domain_model_products.php | 599 ++++++++++++++++ ...gproducts_domain_model_productvariants.php | 665 +++++++++++++++++ ...ducts_domain_model_productvariantsizes.php | 158 ++++ ...ducts_domain_model_selectableattribute.php | 116 +++ Configuration/TsConfig/Page/All.tsconfig | 4 + Configuration/TsConfig/Page/Wizards.tsconfig | 46 ++ .../TypoScript/Base/constants.typoscript | 14 + .../TypoScript/Base/setup.typoscript | 115 +++ .../TypoScript/Breadcrumb/setup.typoscript | 41 ++ .../TypoScript/Canonical/setup.typoscript | 48 ++ .../GoogleAnalytics/constants.typoscript | 0 .../GoogleAnalytics/setup.typoscript | 46 ++ Configuration/TypoScript/constants.typoscript | 2 + Configuration/TypoScript/setup.typoscript | 3 + LICENSE | 9 + README.md | 2 + Resources/Private/.htaccess | 11 + Resources/Private/Language/de.locallang.xlf | 36 + ...h_tx_a2gproducts_domain_model_products.xlf | 63 ++ .../Private/Language/de.locallang_db.xlf | 308 ++++++++ Resources/Private/Language/locallang.xlf | 29 + ...tx_a2gproducts_domain_model_categories.xlf | 20 + ...a2gproducts_domain_model_filteroptions.xlf | 17 + ...sh_tx_a2gproducts_domain_model_filters.xlf | 23 + ..._a2gproducts_domain_model_filtervalues.xlf | 14 + ...h_tx_a2gproducts_domain_model_products.xlf | 47 ++ Resources/Private/Language/locallang_db.xlf | 221 ++++++ Resources/Private/Layouts/Ajax.html | 5 + Resources/Private/Layouts/Default.html | 5 + .../Partials/ContentElements/Masonry.html | 54 ++ .../Private/Partials/Default/AjaxList.html | 2 + Resources/Private/Partials/Default/List.html | 12 + .../Default/Products/List/Filter.html | 34 + .../Partials/Default/Products/List/List.html | 24 + .../Partials/Default/Products/Properties.html | 58 ++ Resources/Private/Partials/Default/Show.html | 42 ++ .../Partials/FilterElements/Checkbox.html | 20 + .../Partials/FilterElements/FilterGroups.html | 46 ++ .../Partials/FilterElements/RangeSlider.html | 16 + .../Partials/FilterElements/Selectbox.html | 16 + Resources/Private/Partials/Image.html | 80 +++ .../Partials/ListElements/CardContent.html | 42 ++ .../Partials/ListElements/Ingredients.html | 24 + .../Partials/ListElements/LoadMoreButton.html | 7 + .../Partials/ListElements/NoProductFound.html | 5 + Resources/Private/Partials/Slider/Images.html | 22 + .../Private/Partials/Slider/Ingredients.html | 23 + .../Private/Partials/Slider/Products.html | 22 + .../Private/Partials/StyleOne/AjaxList.html | 2 + Resources/Private/Partials/StyleOne/List.html | 6 + .../StyleOne/Products/List/Filter.html | 48 ++ .../Partials/StyleOne/Products/List/List.html | 23 + .../StyleOne/Products/Properties.html | 81 +++ Resources/Private/Partials/StyleOne/Show.html | 51 ++ .../Private/Templates/Ingredients/List.html | 13 + .../Private/Templates/Ingredients/Show.html | 87 +++ .../Private/Templates/Products/AjaxList.html | 7 + .../Private/Templates/Products/List.html | 6 + .../Private/Templates/Products/Show.html | 6 + Resources/Public/Icons/Extension.png | Bin 0 -> 47066 bytes Resources/Public/Icons/a2g.gif | Bin 0 -> 1362 bytes Resources/Public/Icons/brand-image.png | Bin 0 -> 3895 bytes Resources/Public/Icons/categories.png | Bin 0 -> 2926 bytes Resources/Public/Icons/filter-option.png | Bin 0 -> 2311 bytes Resources/Public/Icons/filters.png | Bin 0 -> 2140 bytes .../Icons/fingerprint-outline-variant.png | Bin 0 -> 2374 bytes .../Public/Icons/natural-ingredients.png | Bin 0 -> 21211 bytes Resources/Public/Icons/online-shopping.png | Bin 0 -> 19038 bytes Resources/Public/Icons/package.png | Bin 0 -> 2219 bytes Resources/Public/Icons/tag.png | Bin 0 -> 1885 bytes .../GoogleAnalytics/A2gGaEcommerce.js | 17 + .../google-analytics/GaCheckout.js | 73 ++ .../google-analytics/GaCheckout.min.js | 1 + .../google-analytics/GaProduct.js | 145 ++++ .../google-analytics/GaProduct.min.js | 1 + .../google-analytics/GaProducts.js | 125 ++++ .../google-analytics/GaProducts.min.js | 1 + .../google-analytics/GaPromotion.js | 55 ++ .../google-analytics/GaPromotion.min.js | 1 + .../google-analytics/GaPromotions.js | 62 ++ .../google-analytics/GaPromotions.min.js | 1 + .../google-analytics/GaPurchase.js | 67 ++ .../google-analytics/GaPurchase.min.js | 1 + .../google-analytics/GaRefund.js | 44 ++ .../google-analytics/GaRefund.min.js | 44 ++ .../google-analytics/GaRefunds.js | 57 ++ .../google-analytics/GaRefunds.min.js | 1 + .../GoogleAnalytics/googleanalytics.test.js | 49 ++ .../googleanalytics.test.min.js | 57 ++ .../Public/JavaScript/a2gProductsList.js | 183 +++++ .../JavaScript/a2gProductsSwiper.init.js | 86 +++ Resources/Public/JavaScript/rSlider.min.js | 11 + Resources/Public/Scss/a2gProductsList.css | 134 ++++ Resources/Public/Scss/a2gProductsList.scss | 51 ++ Resources/Public/Scss/rSlider.min.scss | 1 + composer.json | 47 ++ ext_emconf.php | 30 + ext_localconf.php | 131 ++++ ext_tables.php | 52 ++ ext_tables.sql | 170 +++++ 150 files changed, 10942 insertions(+) create mode 100755 Classes/Controller/IngredientsController.php create mode 100755 Classes/Controller/ProductsController.php create mode 100755 Classes/Domain/Model/Brands.php create mode 100755 Classes/Domain/Model/Categories.php create mode 100755 Classes/Domain/Model/FilterOptions.php create mode 100755 Classes/Domain/Model/FilterValues.php create mode 100755 Classes/Domain/Model/Filters.php create mode 100755 Classes/Domain/Model/Ingredients.php create mode 100755 Classes/Domain/Model/MasonryItem.php create mode 100755 Classes/Domain/Model/ProductVariantSizes.php create mode 100755 Classes/Domain/Model/ProductVariants.php create mode 100755 Classes/Domain/Model/Products.php create mode 100755 Classes/Domain/Model/SelectableAttribute.php create mode 100755 Classes/Domain/Repository/CategoriesRepository.php create mode 100755 Classes/Domain/Repository/FilterOptionsRepository.php create mode 100755 Classes/Domain/Repository/FiltersRepository.php create mode 100755 Classes/Domain/Repository/IngredientsRepository.php create mode 100755 Classes/Domain/Repository/ProductVariantsRepository.php create mode 100755 Classes/Domain/Repository/ProductsRepository.php create mode 100755 Classes/Domain/Traits/InjectCategoriesRepositoryTrait.php create mode 100755 Classes/Domain/Traits/InjectContentObjectRendererTrait.php create mode 100755 Classes/Domain/Traits/InjectFilterOptionsRepositoryTrait.php create mode 100755 Classes/Domain/Traits/InjectFiltersRepositoryTrait.php create mode 100755 Classes/Domain/Traits/InjectImageServiceTrait.php create mode 100755 Classes/Domain/Traits/InjectIngredientsRepositoryTrait.php create mode 100755 Classes/Domain/Traits/InjectProductsRepositoryTrait.php create mode 100755 Classes/Hreflang/EventListener/ProductsHrefLang.php create mode 100755 Classes/PageTitle/A2gPageTitleProvider.php create mode 100755 Classes/Services/FeuserSessionService.php create mode 100755 Classes/User/FilterValuesMatcher.php create mode 100755 Classes/User/Tca.php create mode 100755 Classes/User/TypoScript.php create mode 100755 Classes/Utility/CanonicalUtility.php create mode 100755 Classes/ViewHelpers/FilterActiveViewHelper.php create mode 100755 Configuration/.htaccess create mode 100755 Configuration/Extbase/Persistence/Classes.php create mode 100755 Configuration/FlexForms/flexform_detail.xml create mode 100755 Configuration/FlexForms/flexform_ingredients_detail.xml create mode 100755 Configuration/FlexForms/flexform_ingredients_list.xml create mode 100755 Configuration/FlexForms/flexform_list.xml create mode 100755 Configuration/Services.yml create mode 100755 Configuration/TCA/Overrides/100_sys_template.php create mode 100755 Configuration/TCA/Overrides/102_tt_content.php create mode 100755 Configuration/TCA/Overrides/500_cropping.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_brands.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_categories.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_filteroptions.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_filters.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_filtervalues.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_ingredients.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_products.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_productvariants.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_productvariantsizes.php create mode 100755 Configuration/TCA/tx_a2gproducts_domain_model_selectableattribute.php create mode 100755 Configuration/TsConfig/Page/All.tsconfig create mode 100755 Configuration/TsConfig/Page/Wizards.tsconfig create mode 100755 Configuration/TypoScript/Base/constants.typoscript create mode 100755 Configuration/TypoScript/Base/setup.typoscript create mode 100755 Configuration/TypoScript/Breadcrumb/setup.typoscript create mode 100755 Configuration/TypoScript/Canonical/setup.typoscript create mode 100755 Configuration/TypoScript/GoogleAnalytics/constants.typoscript create mode 100755 Configuration/TypoScript/GoogleAnalytics/setup.typoscript create mode 100755 Configuration/TypoScript/constants.typoscript create mode 100755 Configuration/TypoScript/setup.typoscript create mode 100755 LICENSE create mode 100755 README.md create mode 100755 Resources/Private/.htaccess create mode 100755 Resources/Private/Language/de.locallang.xlf create mode 100755 Resources/Private/Language/de.locallang_csh_tx_a2gproducts_domain_model_products.xlf create mode 100755 Resources/Private/Language/de.locallang_db.xlf create mode 100755 Resources/Private/Language/locallang.xlf create mode 100755 Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_categories.xlf create mode 100755 Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filteroptions.xlf create mode 100755 Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filters.xlf create mode 100755 Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filtervalues.xlf create mode 100755 Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_products.xlf create mode 100755 Resources/Private/Language/locallang_db.xlf create mode 100755 Resources/Private/Layouts/Ajax.html create mode 100755 Resources/Private/Layouts/Default.html create mode 100755 Resources/Private/Partials/ContentElements/Masonry.html create mode 100755 Resources/Private/Partials/Default/AjaxList.html create mode 100755 Resources/Private/Partials/Default/List.html create mode 100755 Resources/Private/Partials/Default/Products/List/Filter.html create mode 100755 Resources/Private/Partials/Default/Products/List/List.html create mode 100755 Resources/Private/Partials/Default/Products/Properties.html create mode 100755 Resources/Private/Partials/Default/Show.html create mode 100755 Resources/Private/Partials/FilterElements/Checkbox.html create mode 100755 Resources/Private/Partials/FilterElements/FilterGroups.html create mode 100755 Resources/Private/Partials/FilterElements/RangeSlider.html create mode 100755 Resources/Private/Partials/FilterElements/Selectbox.html create mode 100755 Resources/Private/Partials/Image.html create mode 100755 Resources/Private/Partials/ListElements/CardContent.html create mode 100755 Resources/Private/Partials/ListElements/Ingredients.html create mode 100755 Resources/Private/Partials/ListElements/LoadMoreButton.html create mode 100755 Resources/Private/Partials/ListElements/NoProductFound.html create mode 100755 Resources/Private/Partials/Slider/Images.html create mode 100755 Resources/Private/Partials/Slider/Ingredients.html create mode 100755 Resources/Private/Partials/Slider/Products.html create mode 100755 Resources/Private/Partials/StyleOne/AjaxList.html create mode 100755 Resources/Private/Partials/StyleOne/List.html create mode 100755 Resources/Private/Partials/StyleOne/Products/List/Filter.html create mode 100755 Resources/Private/Partials/StyleOne/Products/List/List.html create mode 100755 Resources/Private/Partials/StyleOne/Products/Properties.html create mode 100755 Resources/Private/Partials/StyleOne/Show.html create mode 100755 Resources/Private/Templates/Ingredients/List.html create mode 100755 Resources/Private/Templates/Ingredients/Show.html create mode 100755 Resources/Private/Templates/Products/AjaxList.html create mode 100755 Resources/Private/Templates/Products/List.html create mode 100755 Resources/Private/Templates/Products/Show.html create mode 100755 Resources/Public/Icons/Extension.png create mode 100755 Resources/Public/Icons/a2g.gif create mode 100755 Resources/Public/Icons/brand-image.png create mode 100755 Resources/Public/Icons/categories.png create mode 100755 Resources/Public/Icons/filter-option.png create mode 100755 Resources/Public/Icons/filters.png create mode 100755 Resources/Public/Icons/fingerprint-outline-variant.png create mode 100755 Resources/Public/Icons/natural-ingredients.png create mode 100755 Resources/Public/Icons/online-shopping.png create mode 100755 Resources/Public/Icons/package.png create mode 100755 Resources/Public/Icons/tag.png create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/A2gGaEcommerce.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProduct.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProduct.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProducts.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProducts.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotion.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotion.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPurchase.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPurchase.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefund.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefund.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.min.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/googleanalytics.test.js create mode 100755 Resources/Public/JavaScript/GoogleAnalytics/googleanalytics.test.min.js create mode 100755 Resources/Public/JavaScript/a2gProductsList.js create mode 100755 Resources/Public/JavaScript/a2gProductsSwiper.init.js create mode 100755 Resources/Public/JavaScript/rSlider.min.js create mode 100755 Resources/Public/Scss/a2gProductsList.css create mode 100755 Resources/Public/Scss/a2gProductsList.scss create mode 100755 Resources/Public/Scss/rSlider.min.scss create mode 100755 composer.json create mode 100755 ext_emconf.php create mode 100755 ext_localconf.php create mode 100755 ext_tables.php create mode 100755 ext_tables.sql diff --git a/Classes/Controller/IngredientsController.php b/Classes/Controller/IngredientsController.php new file mode 100755 index 0000000..09c3d62 --- /dev/null +++ b/Classes/Controller/IngredientsController.php @@ -0,0 +1,114 @@ +, none + */ + +/** + * IngredientsController + */ +class IngredientsController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController { + + use InjectIngredientsRepositoryTrait; + use InjectImageServiceTrait; + + /** + * action list + * + * @return string|object|null|void + */ + public function listAction() { + $ingredients = $this->ingredientsRepository->findAll(); + $this->view->assign('contentObjectUid', $this->configurationManager->getContentObject()->data['uid']); + + $this->view->assign('ingredients', $ingredients); + } + + /** + * action ajaxListAction + * + * @return string|object|null|void + */ + public function ajaxListAction() { + + } + + /** + * action show + * + * @param Ingredients $ingredient + * @return string|object|null|void + */ + public function showAction(Ingredients $ingredient) { + $titleProvider = GeneralUtility::makeInstance(A2gPageTitleProvider::class); + + if(array_key_exists('pageTitleSuffix', $this->settings) && $this->settings['pageTitleSuffix'] !== null && $this->settings['pageTitleSuffix'] !== '' && (strlen($ingredient->getTitle()) + strlen($this->settings['pageTitleSuffix'])) < 66 ){ + $pageTitle = $ingredient->getTitle(). ' ' . $this->settings['pageTitleSuffix']; + } else { + $pageTitle = $ingredient->getTitle(); + } + $titleProvider->setTitle($pageTitle); + $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class); + $description = $contentObject->crop($ingredient->getDescription(), 125 . '|...|' . true); + + $uri = $this->uriBuilder->reset()->setCreateAbsoluteUri(true)->setTargetPageUid( + $GLOBALS['TSFE']->id)->uriFor('show', ['ingredient' => $ingredient], 'Ingredients', 'a2gProducts', 'ingredientsdetail'); + + + $this->view->assign('contentObjectUid', $this->configurationManager->getContentObject()->data['uid']); + + $metaTagManager = GeneralUtility::makeInstance(MetaTagManagerRegistry::class); + + /* TODO change + $metaTagManager->getManagerForProperty('robots')->addProperty('robots', 'index, folow'); + $metaTagManager->getManagerForProperty('og:type')->addProperty('og:type', 'website'); + $metaTagManager->getManagerForProperty('twitter:card')->addProperty('twitter:card', 'summary_large_image'); + + if ($ingredient->getTitle() !== '') { + $metaTagManager->getManagerForProperty('title')->addProperty('title', $pageTitle); + $metaTagManager->getManagerForProperty('og:title')->addProperty('og:title', $pageTitle); + $metaTagManager->getManagerForProperty('twitter:title')->addProperty('twitter:title', $pageTitle); + } + if ($ingredient->getDescription() !== '') { + $metaTagManager->getManagerForProperty('description')->addProperty('description', $description); + $metaTagManager->getManagerForProperty('og:description')->addProperty('og:description', $description); + $metaTagManager->getManagerForProperty('twitter:description')->addProperty('twitter:description', $description); + } + $metaTagManager->getManagerForProperty('og:url')->addProperty('og:url', $uri); + $metaTagManager->getManagerForProperty('twitter:url')->addProperty('twitter:url', $uri); + + if ($ingredient->getImage() !== null) { + $processedImage = $this->imageService->applyProcessingInstructions( + $this->imageService->getImage('', $ingredient->getImage(), false), + ['width' => ' + 1200', 'height' => '630c'] + ); + $metaTagManager->getManagerForProperty('twitter:image')->addProperty('twitter:image', $this->imageService->getImageUri($processedImage, true)); + $metaTagManager->getManagerForProperty('og:image')->addProperty('og:image', $this->imageService->getImageUri($processedImage, true)); + } + */ + $this->view->assign('ingredient', $ingredient); + } + +} diff --git a/Classes/Controller/ProductsController.php b/Classes/Controller/ProductsController.php new file mode 100755 index 0000000..43dbde4 --- /dev/null +++ b/Classes/Controller/ProductsController.php @@ -0,0 +1,222 @@ +, none + */ + +/** + * ProductsController + */ +class ProductsController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController { + + use InjectProductsRepositoryTrait; + use InjectFiltersRepositoryTrait; + use InjectCategoriesRepositoryTrait; + use InjectImageServiceTrait; + + use SetMetaTagsTrait; + /** + * @var FeuserSessionService + */ + protected $feuserSessionService = null; + + /** + * @param FeuserSessionService $feuserSessionService + */ + public function injectFeuserSessionService(FeuserSessionService $feuserSessionService) { + $this->feuserSessionService = $feuserSessionService; + } + + /** + * mapInt + * + * @param string $int + * @return int|null + */ + static function mapInt(string $int): ?int { + if (MathUtility::canBeInterpretedAsInteger($int)) { + return (int) $int; + } + return null; + } + + /** + * + * @param \TYPO3\CMS\Extbase\DomainObject\AbstractEntity $obj + * @return int|null + */ + static function mapGetUid(\TYPO3\CMS\Extbase\DomainObject\AbstractEntity $obj): ?int { + return $obj->getUid(); + } + + /** + * action list + * + * @return string|object|null|void + */ + public function listAction() { + $uniqid = $GLOBALS['TSFE']->id . '_' . $this->configurationManager->getContentObject()->data['uid']; + $this->injectFeuserSessionService(new FeuserSessionService('a2gProducts_' . $uniqid . '_')); + $activFilter = $this->feuserSessionService->get('filter'); + $searchField = $this->feuserSessionService->get('searchField'); + $catUids = array_filter(array_map('self::mapInt', explode(',', $this->settings['showCategories']))); + + $categories = $this->categoriesRepository->findByUids($catUids); + $filters = $this->filtersRepository->getFromCategories($catUids); + if (!empty($activFilter)) { + if ((int) $this->settings['ajaxListLimit'] === 0) { + $products = $this->productsRepository->filter($catUids, $activFilter, $searchField, 0, 0, $filters); + } else { + $products = $this->productsRepository->filter($catUids, $activFilter, $searchField, $this->settings['ajaxListLimit'] + 2, 0, $filters); + } + } else { + if ((int) $this->settings['ajaxListLimit'] === 0) { + $products = $this->productsRepository->getFromCategories($catUids); + } else { + $products = $this->productsRepository->getFromCategories($catUids, (int) $this->settings['ajaxListLimit'] + 2); + } + } + $this->view->assign('contentObjectUid', $this->configurationManager->getContentObject()->data['uid']); + + $this->view->assign('categories', $categories); + $this->view->assign('filters', $filters); + $this->view->assign('activeFilter', $activFilter); + $this->view->assign('searchField', $searchField); + $this->view->assign('products', $products); + $this->view->assign('uniqid', $uniqid); + } + + /** + * action ajaxListAction + * + * @return string|object|null|void + */ + public function ajaxListAction() { + $this->injectFeuserSessionService(new FeuserSessionService('a2gProducts_' . (string) $_POST['tx_a2gproducts_a2gproductlist']['uniqid'] . '_')); + $uniqid = $GLOBALS['TSFE']->id . '_' . $this->configurationManager->getContentObject()->data['uid']; + $settings = [ + 'detailPage' => $_POST['tx_a2gproducts_a2gproductlist']['dp'], + 'showCategories' => $_POST['tx_a2gproducts_a2gproductlist']['sc'], + 'style' => $_POST['tx_a2gproducts_a2gproductlist']['style'], + 'ajaxListLimit' => (int) $_POST['tx_a2gproducts_a2gproductlist']['limit'] + ]; + + $catUids = array_filter(array_map('self::mapInt', explode(',', $_POST['tx_a2gproducts_a2gproductlist']['sc']))); + $filters = $this->filtersRepository->getFromCategories($catUids); + + if (array_key_exists('filter',$_POST['tx_a2gproducts_a2gproductlist']) && $_POST['tx_a2gproducts_a2gproductlist']['filter'] === null) { + $filter = []; + } else { + $filter = $_POST['tx_a2gproducts_a2gproductlist']['filter']; + } + + $this->feuserSessionService->set($filter, 'filter'); + $this->feuserSessionService->set($_POST['tx_a2gproducts_a2gproductlist']['searchField'], 'searchField'); + + // duplicate from listAction make a new function !! + if (!empty($filter) || $_POST['tx_a2gproducts_a2gproductlist']['searchField'] !== '') { + if ((int) $settings['ajaxListLimit'] === 0) { + $products = $this->productsRepository->filter($catUids, $filter, $_POST['tx_a2gproducts_a2gproductlist']['searchField'], 0, 0, $filters); + } else { + $products = $this->productsRepository->filter($catUids, $filter, $_POST['tx_a2gproducts_a2gproductlist']['searchField'], $settings['ajaxListLimit'] + 2, (int) $_POST['tx_a2gproducts_a2gproductlist']['loads'] * $settings['ajaxListLimit'], $filters); + } + } else { + if ((int) $settings['ajaxListLimit'] === 0) { + $products = $this->productsRepository->getFromCategories($catUids); + } else { + $products = $this->productsRepository->getFromCategories($catUids, $settings['ajaxListLimit'] + 2, (int) $_POST['tx_a2gproducts_a2gproductlist']['loads'] * $settings['ajaxListLimit']); + } + } + + $this->view->assign('products', $products); + $this->view->assign('filters', $filters); + $this->view->assign('settings', $settings); + } + + static protected function isAllowedCategory(\A2G\A2gProducts\Domain\Model\Products $product, $categories){ + + } + + /** + * action show + * + * @param \A2G\A2gProducts\Domain\Model\Products $product + * @param \A2G\A2gProducts\Domain\Model\ProductVariants $productVariant + * @return string|object|null|void + */ + public function showAction(\A2G\A2gProducts\Domain\Model\Products $product = null, \A2G\A2gProducts\Domain\Model\ProductVariants $productVariant = null) { + + + + if($product === null){ + return GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Controller\ErrorController::class) + ->pageNotFoundAction( + $GLOBALS['TYPO3_REQUEST'], + 'Shop Product not found!', + ['code' => \TYPO3\CMS\Frontend\Page\PageAccessFailureReasons::INVALID_PAGE_ARGUMENTS] + ); + } + + $titleProvider = GeneralUtility::makeInstance(A2gPageTitleProvider::class); + $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class); + $description = $contentObject->crop($product->getDescription(), 125 . '|...|' . true); + $imageUri=null; + if ($product->getImage() !== null) { + $processedImage = $this->imageService->applyProcessingInstructions( + $this->imageService->getImage('', $product->getImage(), false), + ['width' => '1200c', 'height' => '630'] + ); + $imageUri = $this->imageService->getImageUri($processedImage, true); + } + + $this->view->assign('product', $product); + + if($productVariant === null){ + $uri = $this->uriBuilder->reset()->setCreateAbsoluteUri(true)->setTargetPageUid( + $GLOBALS['TSFE']->id)->uriFor('show', ['product' => $product], 'Products', 'a2gShop', 'A2gproductsdetail'); + } else { + $uri = $this->uriBuilder->reset()->setCreateAbsoluteUri(true)->setTargetPageUid( + $GLOBALS['TSFE']->id)->uriFor('show', ['product' => $product, 'productVariant' => $productVariant], 'Products', 'a2gShop', 'A2gproductsdetail'); + } + if($productVariant !== null && array_key_exists('pageTitleSuffix', $this->settings) && $this->settings['pageTitleSuffix'] !== '' && (strlen($product->getTitle()) + (strlen($productVariant->getTitle()) + strlen($this->settings['pageTitleSuffix'])) < 65 )){ + $titleProvider->setTitle($product->getTitle() . ' ' .$productVariant->getTitle() .' - ' . $this->settings['pageTitleSuffix']); + $this->setMetaTags($product->getTitle(). ' ' .$productVariant->getTitle() .' - ' . $this->settings['pageTitleSuffix'], $description, $uri, $imageUri); + } else if($productVariant !== null && (strlen($product->getTitle()) + strlen($productVariant->getTitle())) < 65 ){ + $titleProvider->setTitle($product->getTitle() . ' ' .$productVariant->getTitle()); + $this->setMetaTags($product->getTitle(). ' ' .$productVariant->getTitle(), $description, $uri, $imageUri); + }else if(array_key_exists('pageTitleSuffix', $this->settings) && $this->settings['pageTitleSuffix'] !== '' && (strlen($product->getTitle()) + strlen($this->settings['pageTitleSuffix'])) < 66 ){ + $titleProvider->setTitle($product->getTitle() .' - ' . $this->settings['pageTitleSuffix']); + $this->setMetaTags($product->getTitle() .' - ' . $this->settings['pageTitleSuffix'], $description, $uri, $imageUri); + } else { + $titleProvider->setTitle($product->getTitle()); + $this->setMetaTags($product->getTitle(), $description, $uri, $imageUri); + } + if(!array_key_exists('listPage', $this->settings)){ + $this->view->assign('contentObjectUid', $this->configurationManager->getContentObject()->data['uid']); + } + } + +} diff --git a/Classes/Domain/Model/Brands.php b/Classes/Domain/Model/Brands.php new file mode 100755 index 0000000..0742fab --- /dev/null +++ b/Classes/Domain/Model/Brands.php @@ -0,0 +1,104 @@ +, none + */ + +/** + * Brands + */ +class Brands extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + + /** + * title + * + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $title = ''; + + + /** + * image + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $image = null; + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) { + $this->title = $title; + } + + /** + * Returns the image + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + */ + public function getImage() { + if ($this->image instanceof LazyLoadingProxy) { + $this->image = $this->image->_loadRealInstance(); + } + return $this->image; + } + + /** + * Sets the image + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + * @return void + */ + public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) { + $this->image = $image; + } + + /** + * __construct + */ + public function __construct() { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() { + + } + +} diff --git a/Classes/Domain/Model/Categories.php b/Classes/Domain/Model/Categories.php new file mode 100755 index 0000000..c1d6945 --- /dev/null +++ b/Classes/Domain/Model/Categories.php @@ -0,0 +1,180 @@ +, none + */ + +/** + * Categories + */ +class Categories extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity +{ + + /** + * title + * + * @var string + */ + protected $title = ''; + + /** + * description + * + * @var string + */ + protected $description = ''; + + /** + * image + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + */ + protected $image = null; + + /** + * relFilters + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Filters> + */ + protected $relFilters = null; + + /** + * __construct + */ + public function __construct() + { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() + { + $this->relFilters = $this->relFilters ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + } + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() + { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) + { + $this->title = $title; + } + + /** + * Returns the description + * + * @return string $description + */ + public function getDescription() + { + return $this->description; + } + + /** + * Sets the description + * + * @param string $description + * @return void + */ + public function setDescription(string $description) + { + $this->description = $description; + } + + /** + * Returns the image + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + */ + public function getImage() + { + return $this->image; + } + + /** + * Sets the image + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + * @return void + */ + public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) + { + $this->image = $image; + } + + /** + * Adds a Filters + * + * @param \A2G\A2gProducts\Domain\Model\Filters $relFilter + * @return void + */ + public function addRelFilter(\A2G\A2gProducts\Domain\Model\Filters $relFilter) + { + $this->relFilters->attach($relFilter); + } + + /** + * Removes a Filters + * + * @param \A2G\A2gProducts\Domain\Model\Filters $relFilterToRemove The Filters to be removed + * @return void + */ + public function removeRelFilter(\A2G\A2gProducts\Domain\Model\Filters $relFilterToRemove) + { + $this->relFilters->detach($relFilterToRemove); + } + + /** + * Returns the relFilters + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Filters> $relFilters + */ + public function getRelFilters() + { + return $this->relFilters; + } + + /** + * Sets the relFilters + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Filters> $relFilters + * @return void + */ + public function setRelFilters(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relFilters) + { + $this->relFilters = $relFilters; + } +} diff --git a/Classes/Domain/Model/FilterOptions.php b/Classes/Domain/Model/FilterOptions.php new file mode 100755 index 0000000..2cb4e1a --- /dev/null +++ b/Classes/Domain/Model/FilterOptions.php @@ -0,0 +1,120 @@ +, none + */ + +/** + * FilterOptions + */ +class FilterOptions extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity +{ + + /** + * title + * + * @var string + */ + protected $title = ''; + + /** + * valueMin + * + * @var float + */ + protected $valueMin = 0.0; + + /** + * valueMax + * + * @var float + */ + protected $valueMax = 0.0; + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() + { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) + { + $this->title = $title; + } + + /** + * Returns the valueMin + * + * @return float $valueMin + */ + public function getValueMin() + { + return $this->valueMin; + } + + /** + * Sets the valueMin + * + * @param float $valueMin + * @return void + */ + public function setValueMin(float $valueMin) + { + $this->valueMin = $valueMin; + } + + /** + * Returns the valueMax + * + * @return float $valueMax + */ + public function getValueMax() + { + return $this->valueMax; + } + + /** + * Sets the valueMax + * + * @param float $valueMax + * @return void + */ + public function setValueMax(float $valueMax) + { + $this->valueMax = $valueMax; + } + + /** + * Getter for _localizedUid. + * + * @return int|null The _localizedUid or NULL if none set yet. + */ + public function getLocalizedUid(): ?int + { + if ($this->_localizedUid !== null) { + return (int)$this->_localizedUid; + } + return null; + } + +} diff --git a/Classes/Domain/Model/FilterValues.php b/Classes/Domain/Model/FilterValues.php new file mode 100755 index 0000000..207e00e --- /dev/null +++ b/Classes/Domain/Model/FilterValues.php @@ -0,0 +1,99 @@ +, none + */ + +/** + * FilterValues + */ +class FilterValues extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * value + * + * @var float + */ + protected $value = 0.0; + + /** + * relFilterOptions + * + * @var \A2G\A2gProducts\Domain\Model\FilterOptions + */ + protected $relFilterOption = null; + + /** + * relFilters + * + * @var \A2G\A2gProducts\Domain\Model\Filters + */ + protected $relFilters = null; + + /** + * Returns the value + * + * @return float $value + */ + public function getValue() { + return $this->value; + } + + /** + * Sets the value + * + * @param float $value + * @return void + */ + public function setValue(float $value) { + $this->value = $value; + } + + /** + * Returns the relFilterOption + * + * @return \A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOption + */ + public function getRelFilterOption() { + return $this->relFilterOption; + } + + /** + * Sets the relFilterOption + * + * @param \A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOptio + * @return void + */ + public function setRelFilterOption(\A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOptions) { + $this->relFilterOption = $relFilterOption; + } + + /** + * Returns the relFilters + * + * @return \A2G\A2gProducts\Domain\Model\Filters $relFilters + */ + public function getRelFilters() { + return $this->relFilters; + } + + /** + * Sets the relFilters + * + * @param \A2G\A2gProducts\Domain\Model\Filters $relFilters + * @return void + */ + public function setRelFilters(\A2G\A2gProducts\Domain\Model\Filters $relFilters) { + $this->relFilters = $relFilters; + } + +} diff --git a/Classes/Domain/Model/Filters.php b/Classes/Domain/Model/Filters.php new file mode 100755 index 0000000..6ea9433 --- /dev/null +++ b/Classes/Domain/Model/Filters.php @@ -0,0 +1,234 @@ +, none + */ + +/** + * Filters + */ +class Filters extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity +{ + + /** + * dbOperations + * + * @var array + */ + static public $dbOperations = [ + 1 => '=', + 2 => '>', + 3 => '<', + 4 => '>=', + 5 => '<=', + 6 => 'IN' + ]; + + + /** + * dbType + * + * @var array + */ + static public $dbType = [ + 1 => 'range ( uses min and max value )', + 2 => 'compare ( uses just min value )', + 3 => 'useFilterOptions' + ]; + + /** + * title + * + * @var string + */ + protected $title = ''; + + /** + * filterType + * + * @var int + */ + protected $filterType = ''; + + /** + * dbOperationMax + * + * @var int + */ + protected $dbOperationMax = 0; + + /** + * dbOperationMin + * + * @var int + */ + protected $dbOperationMin = ''; + + /** + * relFilterOption + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterOptions> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + */ + protected $relFilterOption = null; + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() + { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) + { + $this->title = $title; + } + + /** + * Returns the filterType + * + * @return string $filterType + */ + public function getFilterType() + { + return $this->filterType; + } + + /** + * Sets the filterType + * + * @param string $filterType + * @return void + */ + public function setFilterType(string $filterType) + { + $this->filterType = $filterType; + } + + /** + * Returns the dbOperationMax + * + * @return int $dbOperationMax + */ + public function getDbOperationMax() + { + return $this->dbOperationMax; + } + + /** + * Sets the dbOperationMax + * + * @param int $dbOperationMax + * @return void + */ + public function setDbOperationMax(int $dbOperationMax) + { + $this->dbOperationMax = $dbOperationMax; + } + + /** + * Returns the dbOperationMin + * + * @return int dbOperationMin + */ + public function getDbOperationMin() + { + return $this->dbOperationMin; + } + + /** + * Sets the dbOperationMin + * + * @param string $dbOperationMin + * @return void + */ + public function setDbOperationMin(string $dbOperationMin) + { + $this->dbOperationMin = $dbOperationMin; + } + + /** + * __construct + */ + public function __construct() + { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() + { + $this->relFilterOption = $this->relFilterOption ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + } + + /** + * Adds a FilterOptions + * + * @param \A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOption + * @return void + */ + public function addRelFilterOption(\A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOption) + { + $this->relFilterOption->attach($relFilterOption); + } + + /** + * Removes a FilterOptions + * + * @param \A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOptionToRemove The FilterOptions to be removed + * @return void + */ + public function removeRelFilterOption(\A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOptionToRemove) + { + $this->relFilterOption->detach($relFilterOptionToRemove); + } + + /** + * Returns the relFilterOption + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterOptions> $relFilterOption + */ + public function getRelFilterOption() + { + return $this->relFilterOption; + } + + /** + * Sets the relFilterOption + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterOptions> $relFilterOption + * @return void + */ + public function setRelFilterOption(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relFilterOption) + { + $this->relFilterOption = $relFilterOption; + } +} diff --git a/Classes/Domain/Model/Ingredients.php b/Classes/Domain/Model/Ingredients.php new file mode 100755 index 0000000..2376ccb --- /dev/null +++ b/Classes/Domain/Model/Ingredients.php @@ -0,0 +1,303 @@ +, none + */ + +/** + * Ingredients + */ +class Ingredients extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * title + * + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $title = ''; + + /** + * pathSegment + * + * @var string + */ + protected $pathSegment = ''; + + /** + * description + * + * @var string + */ + protected $description = ''; + + /** + * image + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $image = null; + + /** + * images + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $images = null; + + /** + * gallery + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $gallery = null; + + + /** + * relProducts + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relProducts = null; + + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) { + $this->title = $title; + } + + /** + * Returns the pathSegment + * + * @return string $pathSegment + */ + public function getPathSegment() + { + return $this->pathSegment; + } + + /** + * Sets the pathSegment + * + * @param string $pathSegment + * @return void + */ + public function setPathSegment($pathSegment) + { + $this->pathSegment = $pathSegment; + } + + /** + * Returns the description + * + * @return string $description + */ + public function getDescription() { + return $this->description; + } + + /** + * Sets the description + * + * @param string $description + * @return void + */ + public function setDescription(string $description) { + $this->description = $description; + } + + /** + * Returns the image + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + */ + public function getImage() { + if ($this->image instanceof LazyLoadingProxy) { + $this->image = $this->image->_loadRealInstance(); + } + return $this->image; + } + + /** + * Sets the image + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + * @return void + */ + public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) { + $this->image = $image; + } + + /** + * Returns the images + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $images + */ + public function getImages() { + return $this->images; + } + + /** + * Sets the images + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $images + * @return void + */ + public function setImages(\TYPO3\CMS\Extbase\Domain\Model\FileReference $images) { + $this->images = $images; + } + + /** + * Returns the gallery + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery + */ + public function getGallery() { + return $this->gallery; + } + + /** + * Sets the gallery + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery + * @return void + */ + public function setGallery(\TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery) { + $this->gallery = $gallery; + } + + + /** + * __construct + */ + public function __construct() { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() { + $this->gallery = $this->gallery ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->relProducts = $this->relProducts ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + } + + + /** + * Adds a MasonryItem + * + * @param MasonryItem $relMasonryItem + * @return void + */ + public function addGallerys(MasonryItem $relMasonryItem) { + $this->gallery->attach($relMasonryItem); + } + + /** + * Removes a MasonryItem + * + * @param MasonryItem $relMasonryItem The MasonryItem to be removed + * @return void + */ + public function removeGallerys(MasonryItem $relMasonryItem) { + $this->gallery->detach($relMasonryItem); + } + + /** + * Returns the gallery + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage $gallery + */ + public function getGallerys() { + return $this->gallery; + } + + /** + * Sets the gallery + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $gallery + * @return void + */ + public function setGallerys(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $gallery) { + $this->gallery = $gallery; + } + + /** + * Adds a Products + * + * @param Products $relProducts + * @return void + */ + public function addRelProducts(Products $relProducts) { + $this->relProducts->attach($relProducts); + } + + /** + * Removes a Products + * + * @param Products $relProducts The Products to be removed + * @return void + */ + public function removeRelProducts(Products $relProducts) { + $this->relProducts->detach($relProducts); + } + + /** + * Returns the relProducts + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relProducts + */ + public function getRelProducts() { + return $this->relProducts; + } + + /** + * Sets the relProducts + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relProducts + * @return void + */ + public function setRelProducts(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relProducts) { + $this->relProducts = $relProducts; + } +} diff --git a/Classes/Domain/Model/MasonryItem.php b/Classes/Domain/Model/MasonryItem.php new file mode 100755 index 0000000..7c94333 --- /dev/null +++ b/Classes/Domain/Model/MasonryItem.php @@ -0,0 +1,96 @@ +, none + */ + +/** + * MasonryItem + */ +class MasonryItem extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * header + * + * @var string + */ + protected $header = ''; + + /** + * itemClass + * + * @var string + */ + protected $itemClass = ''; + + /** + * image + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $image = null; + + public function getHeader(): string { + return $this->header; + } + + public function getItemClass(): string { + return $this->itemClass; + } + + public function getImage(): \TYPO3\CMS\Extbase\Domain\Model\FileReference { + if ($this->image instanceof LazyLoadingProxy) { + $this->image = $this->image->_loadRealInstance(); + } + return $this->image; + } + + public function setHeader(string $header): void { + $this->header = $header; + } + + public function setItemClass(string $itemClass): void { + $this->itemClass = $itemClass; + } + + public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image): void { + $this->image = $image; + } + + + /** + * __construct + */ + public function __construct() { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() { + $this->relCategory = $this->relCategory ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->relFilterValues = $this->relFilterValues ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + } + +} diff --git a/Classes/Domain/Model/ProductVariantSizes.php b/Classes/Domain/Model/ProductVariantSizes.php new file mode 100755 index 0000000..606a409 --- /dev/null +++ b/Classes/Domain/Model/ProductVariantSizes.php @@ -0,0 +1,180 @@ +, none + */ + +/** + * ProductVariants + */ +class ProductVariantSizes extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * nr + * + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $nr = ''; + + /** + * title + * + * @var string + */ + protected $title = ''; + + /** + * pathSegment + * + * @var string + */ + protected $pathSegment = ''; + + /** + * description + * + * @var string + */ + protected $description = ''; + + /** + * @var ProductVariants + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $productvariant = null; + + /** + * + * @return ProductVariants + */ + public function getProductvariant(): ProductVariants { + if ($this->productvariant instanceof LazyLoadingProxy) { + $this->productvariant = $this->productvariant->_loadRealInstance(); + } + return $this->productvariant; + } + + /** + * + * @param ProductVariants $productvariant + * @return void + */ + public function setProductvariant(ProductVariants $productvariant): void { + $this->productvariant = $productvariant; + } + + + /** + * Returns the nr + * + * @return string $nr + */ + public function getNr() { + return $this->nr; + } + + /** + * Sets the nr + * + * @param string $nr + * @return void + */ + public function setNr(string $nr) { + $this->nr = $nr; + } + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) { + $this->title = $title; + } + + /** + * Returns the pathSegment + * + * @return string $pathSegment + */ + public function getPathSegment() + { + return $this->pathSegment; + } + + /** + * Sets the pathSegment + * + * @param string $pathSegment + * @return void + */ + public function setPathSegment($pathSegment) + { + $this->pathSegment = $pathSegment; + } + + /** + * Returns the description + * + * @return string $description + */ + public function getDescription() { + return $this->description; + } + + /** + * Sets the description + * + * @param string $description + * @return void + */ + public function setDescription(string $description) { + $this->description = $description; + } + + /** + * __construct + */ + public function __construct() { + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() { + } + +} diff --git a/Classes/Domain/Model/ProductVariants.php b/Classes/Domain/Model/ProductVariants.php new file mode 100755 index 0000000..1d802f4 --- /dev/null +++ b/Classes/Domain/Model/ProductVariants.php @@ -0,0 +1,632 @@ +, none + */ + +/** + * ProductVariants + */ +class ProductVariants extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * nr + * + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $nr = ''; + + /** + * title + * + * @var string + */ + protected $title = ''; + + /** + * pathSegment + * + * @var string + */ + protected $pathSegment = ''; + + /** + * description + * + * @var string + */ + protected $description = ''; + + /** + * image + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $image = null; + + /** + * tabIcon + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $tabIcon = null; + + /** + * images + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $images = null; + + /** + * gallery + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $gallery = null; + + /** + * seoImage1x1 + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $seoImage1x1 = null; + /** + * seoImage4x3 + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $seoImage4x3 = null; + /** + * seoImage16x9 + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $seoImage16x9 = null; + + /** + * relCategory + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Categories> + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relCategory = null; + + /** + * relFilterValues + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterValues> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relFilterValues = null; + + /** + * relIngredients + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relIngredients = null; + + + /** + * relFilterValues + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\SelectableAttribute> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relSelectableattribute = null; + + + + /** + * relFilterValues + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\ProductVariantSizes> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relSizes = null; + + /** + * @var Products + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $product = null; + + public function getProduct(): Products { + + if ($this->product instanceof LazyLoadingProxy) { + $this->product = $this->product->_loadRealInstance(); + } + return $this->product; + } + + public function setProduct(Products $product): void { + $this->product = $product; + } + + + /** + * Returns the nr + * + * @return string $nr + */ + public function getNr() { + return $this->nr; + } + + /** + * Sets the nr + * + * @param string $nr + * @return void + */ + public function setNr(string $nr) { + $this->nr = $nr; + } + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) { + $this->title = $title; + } + + /** + * Returns the pathSegment + * + * @return string $pathSegment + */ + public function getPathSegment() + { + return $this->pathSegment; + } + + /** + * Sets the pathSegment + * + * @param string $pathSegment + * @return void + */ + public function setPathSegment($pathSegment) + { + $this->pathSegment = $pathSegment; + } + + /** + * Returns the description + * + * @return string $description + */ + public function getDescription() { + return $this->description; + } + + /** + * Sets the description + * + * @param string $description + * @return void + */ + public function setDescription(string $description) { + $this->description = $description; + } + + /** + * Returns the tabIcon + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $tabIcon + */ + public function getTabIcon() { + if ($this->tabIcon instanceof LazyLoadingProxy) { + $this->tabIcon = $this->tabIcon->_loadRealInstance(); + } + return $this->tabIcon; + } + + /** + * Sets the tabIcon + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $tabIcon + * @return void + */ + public function setTabIcon(\TYPO3\CMS\Extbase\Domain\Model\FileReference $tabIcon) { + $this->tabIcon = $tabIcon; + } + + /** + * Returns the image + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + */ + public function getImage() { + if ($this->image instanceof LazyLoadingProxy) { + $this->image = $this->image->_loadRealInstance(); + } + return $this->image; + } + + /** + * Sets the image + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + * @return void + */ + public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) { + $this->image = $image; + } + + /** + * Returns the images + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $images + */ + public function getImages() { + return $this->images; + } + + /** + * Sets the images + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $images + * @return void + */ + public function setImages(\TYPO3\CMS\Extbase\Domain\Model\FileReference $images) { + $this->images = $images; + } + + + /** + * Returns the gallery + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery + */ + public function getGallery() { + return $this->gallery; + } + + /** + * Sets the gallery + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery + * @return void + */ + public function setGallery(\TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery) { + $this->gallery = $gallery; + } + + + + /** + * Returns the seoImage1x1 + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage1x1 + */ + public function getSeoImage1x1() { + if ($this->seoImage1x1 instanceof LazyLoadingProxy) { + $this->seoImage1x1 = $this->seoImage1x1->_loadRealInstance(); + } + return $this->seoImage1x1; + } + + /** + * Sets the seoImage1x1 + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage1x1 + * @return void + */ + public function setSeoImage1x1(\TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage1x1) { + $this->seoImage1x1 = $seoImage1x1; + } + + /** + * Returns the seoImage4x3 + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage4x3 + */ + public function getSeoImage4x3() { + if ($this->seoImage4x3 instanceof LazyLoadingProxy) { + $this->seoImage4x3 = $this->seoImage4x3->_loadRealInstance(); + } + return $this->seoImage4x3; + } + + /** + * Sets the seoImage4x3 + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage4x3 + * @return void + */ + public function setSeoImage4x3(\TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage4x3) { + $this->seoImage4x3 = $seoImage4x3; + } + + /** + * Returns the seoImage16x9 + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage16x9 + */ + public function getSeoImage16x9() { + if ($this->seoImage16x9 instanceof LazyLoadingProxy) { + $this->seoImage16x9 = $this->seoImage16x9->_loadRealInstance(); + } + return $this->seoImage16x9; + } + + /** + * Sets the seoImage16x9 + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage16x9 + * @return void + */ + public function setSeoImage16x9(\TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage16x9) { + $this->seoImage16x9 = $seoImage16x9; + } + + + /** + * __construct + */ + public function __construct() { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() { + $this->relCategory = $this->relCategory ?: new ObjectStorage(); + $this->relFilterValues = $this->relFilterValues ?: new ObjectStorage(); + $this->relIngredients = $this->relIngredients ?: new ObjectStorage(); + $this->relSelectableattribute = $this->relSelectableattribute ?: new ObjectStorage(); + $this->relSizes = $this->relSizes ?: new ObjectStorage(); + } + + /** + * Adds a Size + * + * @param \A2G\A2gProducts\Domain\Model\ProductVariantSizes $relSizes + * @return void + */ + public function addRelSizes(\A2G\A2gProducts\Domain\Model\ProductVariantSizes $relSizes) { + $this->relSizes->attach($relSizes); + } + + /** + * Removes a Categories + * + * @param \A2G\A2gProducts\Domain\Model\Categories $relSizesToRemove The Categories to be removed + * @return void + */ + public function removeRelSizes(\A2G\A2gProducts\Domain\Model\ProductVariantSizes $relSizesToRemove) { + $this->relSizes->detach($relSizesToRemove); + } + + /** + * Returns the relSizes + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\ProductVariantSizes> $relSizes + */ + public function getRelSizes() { + return $this->relSizes; + } + + /** + * Sets the relSizes + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\ProductVariantSizes> $relSizes + * @return void + */ + public function setRelSizes(ObjectStorage $relSizes) { + $this->relSizes = $relSizes; + } + + /** + * Adds a Categories + * + * @param \A2G\A2gProducts\Domain\Model\Categories $relCategory + * @return void + */ + public function addRelCategory(\A2G\A2gProducts\Domain\Model\Categories $relCategory) { + $this->relCategory->attach($relCategory); + } + + /** + * Removes a Categories + * + * @param \A2G\A2gProducts\Domain\Model\Categories $relCategoryToRemove The Categories to be removed + * @return void + */ + public function removeRelCategory(\A2G\A2gProducts\Domain\Model\Categories $relCategoryToRemove) { + $this->relCategory->detach($relCategoryToRemove); + } + + /** + * Returns the relCategory + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Categories> $relCategory + */ + public function getRelCategory() { + return $this->relCategory; + } + + /** + * Sets the relCategory + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Categories> $relCategory + * @return void + */ + public function setRelCategory(ObjectStorage $relCategory) { + $this->relCategory = $relCategory; + } + + /** + * Adds a FilterValues + * + * @param \A2G\A2gProducts\Domain\Model\FilterValues $relFilterValue + * @return void + */ + public function addRelFilterValue(\A2G\A2gProducts\Domain\Model\FilterValues $relFilterValue) { + $this->relFilterValues->attach($relFilterValue); + } + + /** + * Removes a FilterValues + * + * @param \A2G\A2gProducts\Domain\Model\FilterValues $relFilterValueToRemove The FilterValues to be removed + * @return void + */ + public function removeRelFilterValue(\A2G\A2gProducts\Domain\Model\FilterValues $relFilterValueToRemove) { + $this->relFilterValues->detach($relFilterValueToRemove); + } + + /** + * Returns the relFilterValues + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterValues> $relFilterValues + */ + public function getRelFilterValues() { + return $this->relFilterValues; + } + + /** + * Sets the relFilterValues + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterValues> $relFilterValues + * @return void + */ + public function setRelFilterValues(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relFilterValues) { + $this->relFilterValues = $relFilterValues; + } + + /** + * Adds a FilterValues + * + * @param Ingredients $relIngredients + * @return void + */ + public function addRelIngredients(Ingredients $relIngredients) { + $this->relIngredients->attach($relIngredients); + } + + /** + * Removes a FilterValues + * + * @param Ingredients $relIngredients The Ingredients to be removed + * @return void + */ + public function removeRelIngredients(Ingredients $relIngredients) { + $this->relIngredients->detach($relIngredients); + } + + /** + * Returns the relIngredients + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relIngredients + */ + public function getRelIngredients() { + return $this->relIngredients; + } + + /** + * Sets the relIngredients + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relIngredients + * @return void + */ + public function setRelIngredients(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relIngredients) { + $this->relIngredients = $relIngredients; + } + /** + * Adds a SelectableAttribute + * + * @param \A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattribute + * @return void + */ + public function addRelSelectableattribute(\A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattribute) { + $this->relSelectableattribute->attach($relSelectableattribute); + } + + /** + * Removes a SelectableAttribute + * + * @param \A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattributeToRemove The SelectableAttribute to be removed + * @return void + */ + public function removeRelSelectableattribute(\A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattributeToRemove) { + $this->relSelectableattribute->detach($relSelectableattributeToRemove); + } + + /** + * Returns the relSelectableAttribute + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\SelectableAttribute> $relSelectableattribute + */ + public function getRelSelectableattribute() { + return $this->relSelectableattribute; + } + + /** + * Sets the relSelectableAttribute + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\SelectableAttribute> $relSelectableattribute + * @return void + */ + public function setRelSelectableattribute(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relSelectableattribute) { + $this->relSelectableattribute = $relSelectableattribute; + } +} diff --git a/Classes/Domain/Model/Products.php b/Classes/Domain/Model/Products.php new file mode 100755 index 0000000..acbeb4f --- /dev/null +++ b/Classes/Domain/Model/Products.php @@ -0,0 +1,677 @@ +, none + */ + +/** + * Products + */ +class Products extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * nr + * + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $nr = ''; + + /** + * title + * + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $title = ''; + + /** + * pathSegment + * + * @var string + */ + protected $pathSegment = ''; + + /** + * description + * + * @var string + */ + protected $description = ''; + + /** + * descriptionHtml + * + * @var string + */ + protected $descriptionHtml = ''; + + /** + * image + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $image = null; + + /** + * images + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $images = null; + + /** + * gallery + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $gallery = null; + + + /** + * seoImage1x1 + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $seoImage1x1 = null; + /** + * seoImage4x3 + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $seoImage4x3 = null; + /** + * seoImage16x9 + * + * @var \TYPO3\CMS\Extbase\Domain\Model\FileReference + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $seoImage16x9 = null; + + /** + * relCategory + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Categories> + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relCategory = null; + + /** + * relFilterValues + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterValues> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relFilterValues = null; + + /** + * relIngredients + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relIngredients = null; + + /** + * relProductvariants + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relProductvariants = null; + + /** + * relFilterValues + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\SelectableAttribute> + * @TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove") + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relSelectableattribute = null; + + /** + * relBrand + * + * @var Brands + * @TYPO3\CMS\Extbase\Annotation\ORM\Lazy + */ + protected $relBrand = null; + + /** + * Returns the nr + * + * @return string $nr + */ + public function getNr() { + return $this->nr; + } + + /** + * Sets the nr + * + * @param string $nr + * @return void + */ + public function setNr(string $nr) { + $this->nr = $nr; + } + + /** + * Returns the title + * + * @return string $title + */ + public function getTitle() { + return $this->title; + } + + /** + * Sets the title + * + * @param string $title + * @return void + */ + public function setTitle(string $title) { + $this->title = $title; + } + + /** + * Returns the pathSegment + * + * @return string $pathSegment + */ + public function getPathSegment() { + return $this->pathSegment; + } + + /** + * Sets the pathSegment + * + * @param string $pathSegment + * @return void + */ + public function setPathSegment($pathSegment) { + $this->pathSegment = $pathSegment; + } + + /** + * Returns the description + * + * @return string $description + */ + public function getDescription() { + return $this->description; + } + + /** + * Sets the description + * + * @param string $description + * @return void + */ + public function setDescription(string $description) { + $this->description = $description; + } + + public function getDescriptionHtml(): string { + return $this->descriptionHtml; + } + + public function setDescriptionHtml(string $descriptionHtml): void { + $this->descriptionHtml = $descriptionHtml; + } + + /** + * Returns the image + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + */ + public function getImage() { + if ($this->image instanceof LazyLoadingProxy) { + $this->image = $this->image->_loadRealInstance(); + } + return $this->image; + } + + /** + * Sets the image + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $image + * @return void + */ + public function setImage(\TYPO3\CMS\Extbase\Domain\Model\FileReference $image) { + $this->image = $image; + } + + /** + * Returns the images + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $images + */ + public function getImages() { + return $this->images; + } + + /** + * Sets the images + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $images + * @return void + */ + public function setImages(\TYPO3\CMS\Extbase\Domain\Model\FileReference $images) { + $this->images = $images; + } + + /** + * Returns the gallery + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery + */ + public function getGallery() { + return $this->gallery; + } + + /** + * Sets the gallery + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery + * @return void + */ + public function setGallery(\TYPO3\CMS\Extbase\Domain\Model\FileReference $gallery) { + $this->gallery = $gallery; + } + + + + /** + * Returns the seoImage1x1 + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage1x1 + */ + public function getSeoImage1x1() { + if ($this->seoImage1x1 instanceof LazyLoadingProxy) { + $this->seoImage1x1 = $this->seoImage1x1->_loadRealInstance(); + } + return $this->seoImage1x1; + } + + /** + * Sets the seoImage1x1 + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage1x1 + * @return void + */ + public function setSeoImage1x1(\TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage1x1) { + $this->seoImage1x1 = $seoImage1x1; + } + + /** + * Returns the seoImage4x3 + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage4x3 + */ + public function getSeoImage4x3() { + if ($this->seoImage4x3 instanceof LazyLoadingProxy) { + $this->seoImage4x3 = $this->seoImage4x3->_loadRealInstance(); + } + return $this->seoImage4x3; + } + + /** + * Sets the seoImage4x3 + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage4x3 + * @return void + */ + public function setSeoImage4x3(\TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage4x3) { + $this->seoImage4x3 = $seoImage4x3; + } + + /** + * Returns the seoImage16x9 + * + * @return \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage16x9 + */ + public function getSeoImage16x9() { + if ($this->seoImage16x9 instanceof LazyLoadingProxy) { + $this->seoImage16x9 = $this->seoImage16x9->_loadRealInstance(); + } + return $this->seoImage16x9; + } + + /** + * Sets the seoImage16x9 + * + * @param \TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage16x9 + * @return void + */ + public function setSeoImage16x9(\TYPO3\CMS\Extbase\Domain\Model\FileReference $seoImage16x9) { + $this->seoImage16x9 = $seoImage16x9; + } + + + + + /** + * __construct + */ + public function __construct() { + + // Do not remove the next line: It would break the functionality + $this->initializeObject(); + } + + /** + * Initializes all ObjectStorage properties when model is reconstructed from DB (where __construct is not called) + * Do not modify this method! + * It will be rewritten on each save in the extension builder + * You may modify the constructor of this class instead + * + * @return void + */ + public function initializeObject() { + $this->relCategory = $this->relCategory ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->relFilterValues = $this->relFilterValues ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->relIngredients = $this->relIngredients ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->relSelectableattribute = $this->relSelectableattribute ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->relProductvariants = $this->relProductvariants ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + $this->gallery = $this->gallery ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); +// $this->relBrand = $this->relBrand ?: new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + } + + /** + * Adds a Categories + * + * @param \A2G\A2gProducts\Domain\Model\Categories $relCategory + * @return void + */ + public function addRelCategory(\A2G\A2gProducts\Domain\Model\Categories $relCategory) { + $this->relCategory->attach($relCategory); + } + + /** + * Removes a Categories + * + * @param \A2G\A2gProducts\Domain\Model\Categories $relCategoryToRemove The Categories to be removed + * @return void + */ + public function removeRelCategory(\A2G\A2gProducts\Domain\Model\Categories $relCategoryToRemove) { + $this->relCategory->detach($relCategoryToRemove); + } + + /** + * Returns the relCategory + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Categories> $relCategory + */ + public function getRelCategory() { + return $this->relCategory; + } + + /** + * Sets the relCategory + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\Categories> $relCategory + * @return void + */ + public function setRelCategory(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relCategory) { + $this->relCategory = $relCategory; + } + + /** + * Adds a FilterValues + * + * @param \A2G\A2gProducts\Domain\Model\FilterValues $relFilterValue + * @return void + */ + public function addRelFilterValue(\A2G\A2gProducts\Domain\Model\FilterValues $relFilterValue) { + $this->relFilterValues->attach($relFilterValue); + } + + /** + * Removes a FilterValues + * + * @param \A2G\A2gProducts\Domain\Model\FilterValues $relFilterValueToRemove The FilterValues to be removed + * @return void + */ + public function removeRelFilterValue(\A2G\A2gProducts\Domain\Model\FilterValues $relFilterValueToRemove) { + $this->relFilterValues->detach($relFilterValueToRemove); + } + + /** + * Returns the relFilterValues + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterValues> $relFilterValues + */ + public function getRelFilterValues() { + return $this->relFilterValues; + } + + /** + * Sets the relFilterValues + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\FilterValues> $relFilterValues + * @return void + */ + public function setRelFilterValues(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relFilterValues) { + $this->relFilterValues = $relFilterValues; + } + + /** + * Adds a SelectableAttribute + * + * @param \A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattribute + * @return void + */ + public function addRelSelectableattribute(\A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattribute) { + $this->relSelectableattribute->attach($relSelectableattribute); + } + + /** + * Removes a SelectableAttribute + * + * @param \A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattributeToRemove The SelectableAttribute to be removed + * @return void + */ + public function removeRelSelectableattribute(\A2G\A2gProducts\Domain\Model\SelectableAttribute $relSelectableattributeToRemove) { + $this->relSelectableattribute->detach($relSelectableattributeToRemove); + } + + /** + * Returns the relSelectableAttribute + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\SelectableAttribute> $relSelectableattribute + */ + public function getRelSelectableattribute() { + return $this->relSelectableattribute; + } + + /** + * Sets the relSelectableAttribute + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\A2G\A2gProducts\Domain\Model\SelectableAttribute> $relSelectableattribute + * @return void + */ + public function setRelSelectableattribute(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relSelectableattribute) { + $this->relSelectableattribute = $relSelectableattribute; + } + + /** + * Adds a FilterValues + * + * @param Ingredients $relIngredients + * @return void + */ + public function addRelIngredients(Ingredients $relIngredients) { + $this->relIngredients->attach($relIngredients); + } + + /** + * Removes a FilterValues + * + * @param Ingredients $relIngredients The Ingredients to be removed + * @return void + */ + public function removeRelIngredients(Ingredients $relIngredients) { + $this->relIngredients->detach($relIngredients); + } + + /** + * Returns the relIngredients + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relIngredients + */ + public function getRelIngredients() { + return $this->relIngredients; + } + + /** + * Sets the relIngredients + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relIngredients + * @return void + */ + public function setRelIngredients(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relIngredients) { + $this->relIngredients = $relIngredients; + } + + /** + * Adds a MasonryItem + * + * @param MasonryItem $relMasonryItem + * @return void + */ + public function addGallerys(MasonryItem $relMasonryItem) { + $this->gallery->attach($relMasonryItem); + } + + /** + * Removes a MasonryItem + * + * @param MasonryItem $relMasonryItem The MasonryItem to be removed + * @return void + */ + public function removeGallerys(MasonryItem $relMasonryItem) { + $this->gallery->detach($relMasonryItem); + } + + /** + * Returns the gallery + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage $gallery + */ + public function getGallerys() { + return $this->gallery; + } + + /** + * Sets the gallery + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $gallery + * @return void + */ + public function setGallerys(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $gallery) { + $this->gallery = $gallery; + } + +// +// public function getRelProductvariants() { +// return $this->relProductvariants; +// } +// +// public function setRelProductvariants($relProductvariants): void { +// $this->relProductvariants = $relProductvariants; +// } +// +// + + /** + * Adds a FilterValues + * + * @param ProductVariants $relProductvariants + * @return void + */ + public function addRelProductvariants($relProductvariants) { + $this->relProductvariants->attach($relProductvariants); + } + + /** + * Removes a FilterValues + * + * @param ProductVariants $relProductvariants The ProductVariants to be removed + * @return void + */ + public function removeRelProductvariants($relProductvariants) { + $this->relProductvariants->detach($relProductvariants); + } + + /** + * Returns the relProductvariants + * + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relProductvariants + */ + public function getRelProductvariants() { + return $this->relProductvariants; + } + + /** + * Sets the relProductvariants + * + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $relProductvariants + * @return void + */ + public function setRelProductvariants(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $relProductvariants) { + $this->relProductvariants = $relProductvariants; + } + + /** + * Returns the relBrand + * + * @return Brands|null + */ + public function getRelBrand():?Brands { + if ($this->relBrand instanceof LazyLoadingProxy) { + $this->relBrand = $this->relBrand->_loadRealInstance(); + } + return $this->relBrand; + } + + /** + * Sets the relBrand + * + * @param Brands|null $relBrand + * @return void + */ + public function setRelBrand(?Brands $relBrand) { + $this->relBrand = $relBrand; + } +} diff --git a/Classes/Domain/Model/SelectableAttribute.php b/Classes/Domain/Model/SelectableAttribute.php new file mode 100755 index 0000000..66b8985 --- /dev/null +++ b/Classes/Domain/Model/SelectableAttribute.php @@ -0,0 +1,87 @@ +, none + */ + +/** + * SelectableAttribute + */ +class SelectableAttribute extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity { + + /** + * relFilterOptions + * + * @var \A2G\A2gProducts\Domain\Model\FilterOptions + */ + protected $relFilterOption = null; + + /** + * relFilters + * + * @var \A2G\A2gProducts\Domain\Model\Filters + */ + protected $relFilters = null; + + /** + * + * @var string + */ + protected $title = ''; + + /** + * Returns the relFilterOption + * + * @return \A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOption + */ + public function getRelFilterOption() { + return $this->relFilterOption; + } + + /** + * Sets the relFilterOption + * + * @param \A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOptio + * @return void + */ + public function setRelFilterOption(\A2G\A2gProducts\Domain\Model\FilterOptions $relFilterOptions) { + $this->relFilterOption = $relFilterOption; + } + + /** + * Returns the relFilters + * + * @return \A2G\A2gProducts\Domain\Model\Filters $relFilters + */ + public function getRelFilters() { + return $this->relFilters; + } + + /** + * Sets the relFilters + * + * @param \A2G\A2gProducts\Domain\Model\Filters $relFilters + * @return void + */ + public function setRelFilters(\A2G\A2gProducts\Domain\Model\Filters $relFilters) { + $this->relFilters = $relFilters; + } + + public function getTitle(): string { + return $this->title; + } + + public function setTitle(string $title): void { + $this->title = $title; + } + +} diff --git a/Classes/Domain/Repository/CategoriesRepository.php b/Classes/Domain/Repository/CategoriesRepository.php new file mode 100755 index 0000000..5ab96bd --- /dev/null +++ b/Classes/Domain/Repository/CategoriesRepository.php @@ -0,0 +1,43 @@ +, web-crossing gmbh + * + * * */ + +/** + * The repository for Categories + */ +class CategoriesRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + + /** + * @var array + */ + protected $defaultOrderings = [ + 'sorting' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING + ]; + + /** + * @param array $uids + */ + public function findByUids(array $uids = []) { + if (!empty($uids)) { + $query = $this->createQuery(); + $constraints = []; + $constraints[] = $query->in('uid', $uids); + $query->matching($query->logicalAnd($constraints)); + return $query->execute(); + } + } + +} diff --git a/Classes/Domain/Repository/FilterOptionsRepository.php b/Classes/Domain/Repository/FilterOptionsRepository.php new file mode 100755 index 0000000..fe1d6d6 --- /dev/null +++ b/Classes/Domain/Repository/FilterOptionsRepository.php @@ -0,0 +1,30 @@ +, web-crossing gmbh + * + * * */ + +/** + * The repository for FilterOptions + */ +class FilterOptionsRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + + /** + * @var array + */ + protected $defaultOrderings = [ + 'sorting' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING + ]; +} diff --git a/Classes/Domain/Repository/FiltersRepository.php b/Classes/Domain/Repository/FiltersRepository.php new file mode 100755 index 0000000..9b5cb42 --- /dev/null +++ b/Classes/Domain/Repository/FiltersRepository.php @@ -0,0 +1,51 @@ +, none + */ + +/** + * The repository for Products + */ +class FiltersRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + /** + * @var array + */ + + protected $defaultOrderings = [ + 'sorting' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING + ]; + + /** + * @param array $categoryUids + */ + public function getFromCategories(array $categoryUids = []) { + $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language'); + $sys_language_uid = $languageAspect->getId(); + + $query = $this->createQuery(); + $sql = 'SELECT DISTINCT fT.* FROM tx_a2gproducts_domain_model_filters AS fT ' + . 'JOIN tx_a2gproducts_categories_filters_mm AS mmT ON mmT.uid_foreign = fT.uid' + . ' WHERE fT.hidden=0 AND fT.deleted=0 ' + . (empty($categoryUids) ? '' :'AND mmT.uid_local IN (' . implode(',', $categoryUids ) . ') ') + . 'AND fT.sys_language_uid IN (:dcSysLanguageUid, -1) ORDER BY fT.sorting'; + $arguments = [ + ':dcSysLanguageUid' => $sys_language_uid + ]; + $query->statement($sql, $arguments); + return $query->execute(); + } + +} diff --git a/Classes/Domain/Repository/IngredientsRepository.php b/Classes/Domain/Repository/IngredientsRepository.php new file mode 100755 index 0000000..233ad90 --- /dev/null +++ b/Classes/Domain/Repository/IngredientsRepository.php @@ -0,0 +1,33 @@ +, none + */ + +/** + * The repository for Ingredients + */ +class IngredientsRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + + /** + * @var array + */ + protected $defaultOrderings = [ + 'sorting' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING + ]; + + public function initializeObject() { + $querySettings = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings::class); + $querySettings->setRespectStoragePage(false); + $this->setDefaultQuerySettings($querySettings); + } +} diff --git a/Classes/Domain/Repository/ProductVariantsRepository.php b/Classes/Domain/Repository/ProductVariantsRepository.php new file mode 100755 index 0000000..afeed34 --- /dev/null +++ b/Classes/Domain/Repository/ProductVariantsRepository.php @@ -0,0 +1,27 @@ +, none + */ + +/** + * The repository for ProductVariants + */ +class ProductVariantsRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + + /** + * @var array + */ + protected $defaultOrderings = [ + 'sorting' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING + ]; +} diff --git a/Classes/Domain/Repository/ProductsRepository.php b/Classes/Domain/Repository/ProductsRepository.php new file mode 100755 index 0000000..7af0ff4 --- /dev/null +++ b/Classes/Domain/Repository/ProductsRepository.php @@ -0,0 +1,204 @@ +, none + */ + +/** + * The repository for Products + */ +class ProductsRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + + use InjectFiltersRepositoryTrait; + use InjectFilterOptionsRepositoryTrait; + + /** + * @param array $categoryUids + */ + public function getFromCategories(array $categoryUids, int $limit = 0, int $offset = 0, array $excludeProduct = [], bool $random = false) { + if (!empty($categoryUids)) { + $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language'); + $sys_language_uid = $languageAspect->getId(); + $query = $this->createQuery(); + + $sql = ' SELECT DISTINCT pT.* FROM tx_a2gproducts_domain_model_products AS pT ' + . 'JOIN tx_a2gproducts_domain_model_productvariants AS pvT ON pvT.product = pT.uid ' + . 'JOIN tx_a2gproducts_products_categories_mm AS mmT ON mmT.uid_local = pT.uid '; + $sqlWhere = ' WHERE pT.hidden=0 AND pT.deleted=0 AND pvT.hidden=0 AND pvT.deleted=0 AND mmT.uid_foreign IN (' . implode(',', $categoryUids) . ') AND pT.sys_language_uid IN (-1, :dcSysLangUid) '; + $arguments = [ + ':dcSysLangUid' => $sys_language_uid + ]; + + if (!empty($excludeProduct)) { + $sqlWhere .= ' AND pT.uid NOT IN (' . implode(',', $excludeProduct) . ') '; + } + + if ($random) { + $sqlWhere .= ' ORDER BY RAND() '; + } else { + $sqlWhere .= ' ORDER BY pT.sorting '; + } + + + + if ($limit > 0) { + $sqlWhere .= ' LIMIT :dcLimit '; + $arguments[':dcLimit'] = $limit; + } + if ($offset > 0) { + $sqlWhere .= ' OFFSET :dcOffset '; + $arguments[':dcOffset'] = $offset; + } + + $query->statement($sql . $sqlWhere, $arguments); + return $query->execute(); + } else { + return $this->findAll(); + } + } + + /** + * + * @param array $categoryUids + * @param array $mainFilter + * @param string $search + * @param int $limit + * @param int $offset + * @param QueryResult $filters + * @param bool $random + * @return QueryResult + */ + public function filter(array $categoryUids, array $mainFilter = [], string $search = '', int $limit = 0, int $offset = 0, QueryResult $filters = null, bool $random = false): QueryResult { + $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language'); + $sys_language_uid = $languageAspect->getId(); + + $query = $this->createQuery(); + $sql = 'SELECT DISTINCT pT.* FROM tx_a2gproducts_domain_model_products AS pT ' + . 'JOIN tx_a2gproducts_domain_model_productvariants AS pvT ON pvT.product = pT.uid ' + . 'JOIN tx_a2gproducts_products_categories_mm AS mmT ON mmT.uid_local = pT.uid '; + $sqlWhere = 'WHERE pT.hidden=0 AND pT.deleted=0 AND pvT.hidden=0 AND pvT.deleted=0 AND pT.sys_language_uid IN (:dcSysLangUid,-1) '; + if(!empty($categoryUids)){ + $sqlWhere .= 'AND mmT.uid_foreign IN (' . implode(',', $categoryUids) . ') '; + } + $arguments = [ + ':dcSysLangUid' => $sys_language_uid + ]; + + if (trim($search) !== '') { + $sqlWhere .= 'AND pT.title LIKE :dcSearch '; + $arguments[':dcSearch'] = '%' . $search . '%'; + } + + $filtersSortet = []; + foreach ($filters as $filter) { + $filtersSortet[$filter->getUid()] = $filter; + } + $x = 1; + $i = 0; + + $sql1 = ' '; + $sqlWhere1 = ' '; + + foreach ($mainFilter AS $key => $filter) { + if($filtersSortet[$key] === null){ + $mainFilter[$key] = null; + } + } + $mainFilter = array_filter($mainFilter); + if (!empty($mainFilter)) { + $sqlWhere .= ' AND ( '; + foreach ($mainFilter AS $key => $filter) { + $i = 0; + if ($x > 1) { + $sqlWhere .= ' AND '; + } + $sqlWhere .= ' ( '; +// $sqlWhere1 .= ' ( '; + if (!empty($filter)) { + foreach ($filter AS $kay => $opt) { + if ($i > 0) { + $sqlWhere .= ' OR '; + } else { +// $sqlWhere .= ' ( fv' . $x . 'T.hidden = 0 OR fvpv' . $x . 'T.hidden = 0 OR sav' . $x . 'T.hidden = 0 OR savpv' . $x . 'T.hidden = 0 ) AND ( '; + } + $filterOpt = $this->filteroptionRepository->findByUid((int) $kay); + switch ($filtersSortet[$key]->getFilterType()) { + case 1: + // 'range ( uses min and max value )' + $sqlWhere .= ' ( fv' . $x . 'T.value ' . Filters::$dbOperations[$filtersSortet[$key]->getDbOperationMin()] . ' ' . $filterOpt->getValueMin() . ' '; + if ($filterOpt->getValueMax() > 0) { + $sqlWhere .= ' AND fv' . $x . 'T.value ' . Filters::$dbOperations[$filtersSortet[$key]->getDbOperationMax()] . ' ' . $filterOpt->getValueMax(); + } + $sqlWhere .= ' ) '; + break; + case 2: + // 'compare ( uses just min value )' + if (Filters::$dbOperations[$filtersSortet[$key]->getDbOperationMin()] === 'IN') { + $sqlWhere .= '( fv' . $x . 'T.value IN (' . $filterOpt->getValueMin() . ' ) '; + } else { + $sqlWhere .= '( fv' . $x . 'T.value ' . Filters::$dbOperations[$filtersSortet[$key]->getDbOperationMin()] . ' ' . $filterOpt->getValueMin() . ' ) '; + } + break; + case 3: + // uses no value + $sqlWhere .= '( ' + . '( fv' . $x . 'T.rel_filter_option = ' . (int) $kay . ' AND fv' . $x . 'T.hidden = 0 ) ' + . 'OR ( fvpv' . $x . 'T.rel_filter_option = ' . (int) $kay . ' AND fvpv' . $x . 'T.hidden = 0 ) ' +// . 'OR ( sav' . $x . 'T.rel_filter_option = ' . (int) $kay . ' AND sav' . $x . 'T.hidden = 0 ) ' + . 'OR ( savpv' . $x . 'T.rel_filter_option = ' . (int) $kay . ' AND savpv' . $x . 'T.hidden = 0 ) ' + . ') '; + break; + } + $i = 1; + } + +// $sqlWhere .= ' ) '; + } + $sql .= 'LEFT JOIN tx_a2gproducts_domain_model_filtervalues AS fv' . $x . 'T ON fv' . $x . 'T.products = pT.uid ' + . 'LEFT JOIN tx_a2gproducts_domain_model_filtervalues AS fvpv' . $x . 'T ON fvpv' . $x . 'T.productvariants = pvT.uid ' +// . 'LEFT JOIN tx_a2gproducts_domain_model_selectableattribute AS sav' . $x . 'T ON sav' . $x . 'T.products = pT.uid ' + . 'LEFT JOIN tx_a2gproducts_domain_model_selectableattribute AS savpv' . $x . 'T ON savpv' . $x . 'T.productvariants = pvT.uid '; + $arguments[':dcKey' . $x] = (int) $key; + $x = $x + 1; + $sqlWhere .= ' ) '; + } + $sqlWhere .= ' ) '; + } + + if ($random) { + $sqlWhere .= ' ORDER BY RAND()'; + } else { + $sqlWhere .= ' ORDER BY pT.sorting'; + } + + if ($limit > 0) { + $sqlWhere .= ' LIMIT :dcLimit '; + $arguments[':dcLimit'] = $limit; + } + if ($offset > 0) { + $sqlWhere .= ' OFFSET :dcOffset '; + $arguments[':dcOffset'] = $offset; + } + $query->statement($sql . $sqlWhere, $arguments); + return $query->execute(); + } + +} diff --git a/Classes/Domain/Traits/InjectCategoriesRepositoryTrait.php b/Classes/Domain/Traits/InjectCategoriesRepositoryTrait.php new file mode 100755 index 0000000..550443d --- /dev/null +++ b/Classes/Domain/Traits/InjectCategoriesRepositoryTrait.php @@ -0,0 +1,32 @@ +categoriesRepository = $categoriesRepository; + } + +} diff --git a/Classes/Domain/Traits/InjectContentObjectRendererTrait.php b/Classes/Domain/Traits/InjectContentObjectRendererTrait.php new file mode 100755 index 0000000..e80962c --- /dev/null +++ b/Classes/Domain/Traits/InjectContentObjectRendererTrait.php @@ -0,0 +1,33 @@ +contentObjectRenderer = $contentObjectRenderer; + } +} diff --git a/Classes/Domain/Traits/InjectFilterOptionsRepositoryTrait.php b/Classes/Domain/Traits/InjectFilterOptionsRepositoryTrait.php new file mode 100755 index 0000000..31bbf1a --- /dev/null +++ b/Classes/Domain/Traits/InjectFilterOptionsRepositoryTrait.php @@ -0,0 +1,35 @@ +filteroptionRepository = $filteroptionRepository; + } + +} diff --git a/Classes/Domain/Traits/InjectFiltersRepositoryTrait.php b/Classes/Domain/Traits/InjectFiltersRepositoryTrait.php new file mode 100755 index 0000000..e678c8f --- /dev/null +++ b/Classes/Domain/Traits/InjectFiltersRepositoryTrait.php @@ -0,0 +1,31 @@ +filtersRepository = $filtersRepository; + } +} diff --git a/Classes/Domain/Traits/InjectImageServiceTrait.php b/Classes/Domain/Traits/InjectImageServiceTrait.php new file mode 100755 index 0000000..3c7d4c3 --- /dev/null +++ b/Classes/Domain/Traits/InjectImageServiceTrait.php @@ -0,0 +1,35 @@ +imageService = $imageService; + } + +} diff --git a/Classes/Domain/Traits/InjectIngredientsRepositoryTrait.php b/Classes/Domain/Traits/InjectIngredientsRepositoryTrait.php new file mode 100755 index 0000000..b73e408 --- /dev/null +++ b/Classes/Domain/Traits/InjectIngredientsRepositoryTrait.php @@ -0,0 +1,27 @@ +ingredientsRepository = $ingredientsRepository; + } + +} diff --git a/Classes/Domain/Traits/InjectProductsRepositoryTrait.php b/Classes/Domain/Traits/InjectProductsRepositoryTrait.php new file mode 100755 index 0000000..d7ba8fa --- /dev/null +++ b/Classes/Domain/Traits/InjectProductsRepositoryTrait.php @@ -0,0 +1,32 @@ +productsRepository = $productsRepository; + } + +} diff --git a/Classes/Hreflang/EventListener/ProductsHrefLang.php b/Classes/Hreflang/EventListener/ProductsHrefLang.php new file mode 100755 index 0000000..0a1099c --- /dev/null +++ b/Classes/Hreflang/EventListener/ProductsHrefLang.php @@ -0,0 +1,51 @@ +cObj = $cObj; + $this->languageMenuProcessor = $languageMenuProcessor; + } + + + public function __invoke(ModifyHrefLangTagsEvent $event): void + { + $hrefLangs = $event->getHrefLangs(); + $request = $event->getRequest(); + + // Do anything you want with $hrefLangs + $hrefLangs = [ + 'en-US' => 'https://example.com', + 'nl-NL' => 'https://example.com/nl' + ]; + + // Override all hrefLang tags + $event->setHrefLangs($hrefLangs); + + // Or add a single hrefLang tag + $event->addHrefLang('de-DE', 'https://example.com/de'); + } +} diff --git a/Classes/PageTitle/A2gPageTitleProvider.php b/Classes/PageTitle/A2gPageTitleProvider.php new file mode 100755 index 0000000..9c2f433 --- /dev/null +++ b/Classes/PageTitle/A2gPageTitleProvider.php @@ -0,0 +1,22 @@ +title = $title; + } +} \ No newline at end of file diff --git a/Classes/Services/FeuserSessionService.php b/Classes/Services/FeuserSessionService.php new file mode 100755 index 0000000..a758615 --- /dev/null +++ b/Classes/Services/FeuserSessionService.php @@ -0,0 +1,79 @@ +keyPrefix = $keyPrefix; + } + + /** + * Returns the object stored in the user´s PHP session + * @param string $key + * @return type the stored object + */ + public function get(string $key) { + $sessionData = $GLOBALS['TSFE']->fe_user->getKey('ses', $this->keyPrefix . $key); + return unserialize($sessionData); + } + + /** + * Writes an object into the PHP session + * + * @param type $object any serializable object to store into the session + * @param string $key identifier from the store in the session + * @return FeuserSessionService + */ + public function set($object, string $key): FeuserSessionService { + $sessionData = serialize($object); + $GLOBALS['TSFE']->fe_user->setKey('ses', $this->keyPrefix . $key, $sessionData); + $GLOBALS['TSFE']->fe_user->storeSessionData(); + return $this; + } + + /** + * Cleans up the session: removes the stored object from the PHP session + * + * @param type $key identifier from the store in the session to clean + * @return FeuserSessionService + */ + public function clean($key): FeuserSessionService { + $GLOBALS['TSFE']->fe_user->setKey('ses', $this->keyPrefix . $key, NULL); + $GLOBALS['TSFE']->fe_user->storeSessionData(); + return $this; + } + + /** + * set a prefix for your session store keys + * + * @param string $prefixKey + * @return void + */ + public function setKeyPrefix(string $keyPrefix = ''): void { + $this->keyPrefix = $keyPrefix; + } + +} diff --git a/Classes/User/FilterValuesMatcher.php b/Classes/User/FilterValuesMatcher.php new file mode 100755 index 0000000..fde0c41 --- /dev/null +++ b/Classes/User/FilterValuesMatcher.php @@ -0,0 +1,127 @@ +conRegistration = $conPool->getConnectionForTable('tx_a2gproducts_domain_model_filtervalues'); + } + + /** + * @param type $parameters + * @param type $parentObject + * @return bool + */ + public function showOptionsSelect(&$parameters, $parentObject): bool { + try { + $sql = 'SELECT count(foT.uid) as count ' + . 'FROM tx_a2gproducts_domain_model_filteroptions AS foT ' + . 'JOIN tx_a2gproducts_domain_model_filters AS fT ON fT.uid = foT.filters ' + . 'WHERE fT.uid = ? AND fT.filter_type=3 AND foT.hidden = 0 AND foT.deleted=0'; + $stmt = $this->conRegistration->prepare($sql); + $stmt->bindValue(1, (int) $parameters['record']['rel_filters'][0]); + $stmt->execute(); + $tmp = $stmt->fetchAll(); + if ($tmp[0] !== null) { + return (bool) $tmp[0]['count']; + } else { + return false; + } + } catch (\Exception $e) { + return false; + } + } + + /** + * + * @param type $parameters + * @param type $parentObject + * @return bool + */ + public function showValueInput(&$parameters, $parentObject): bool { + + try { + $sql = 'SELECT count(foT.uid) as count ' + . 'FROM tx_a2gproducts_domain_model_filteroptions AS foT ' + . 'JOIN tx_a2gproducts_domain_model_filters AS fT ON fT.uid = foT.filters ' + . 'WHERE fT.uid = ? AND fT.filter_type IN ( 1,2 ) AND foT.hidden = 0 AND foT.deleted=0 AND foT.sys_language_uid = 0'; + $stmt = $this->conRegistration->prepare($sql); + $stmt->bindValue(1, (int) $parameters['record']['rel_filters'][0]); + $stmt->execute(); + $tmp = $stmt->fetchAll(); + if ($tmp[0] !== null) { + return (bool) $tmp[0]['count']; + } else { + return false; + } + } catch (\Exception $e) { + return false; + } + } + + /** + * + * @param type $parameters + * @param type $parentObject + * @return void + */ + public function title(&$parameters, $parentObject):void { + try { + if(array_key_exists('rel_filters', $parameters['row']){ + if(array_key_exists(0,$parameters['row']['rel_filters'])){ + $sql2 = 'SELECT fT.title AS title ' + . 'FROM tx_a2gproducts_domain_model_filters AS fT ' + . ' WHERE fT.uid = ? AND fT.deleted = 0 AND fT.hidden = 0'; + $stmt2 = $this->conRegistration->prepare($sql2); + $stmt2->bindValue(1, (int) $parameters['row']['rel_filters'][0]); + $stmt2->execute(); + $tmp2 = $stmt2->fetchAll(); + if (array_key_exists(0, $tmp2)) { + $out = $tmp2[0]['title']; + } else { + $out = ''; + } + $sql = 'SELECT fT.title AS title ' + . 'FROM tx_a2gproducts_domain_model_filteroptions AS fT ' + . ' WHERE fT.uid = ? AND fT.deleted = 0 AND fT.hidden = 0'; + $stmt = $this->conRegistration->prepare($sql); + $stmt->bindValue(1, (int) $parameters['row']['rel_filter_option'][0]); + $stmt->execute(); + $tmp = $stmt->fetchAll(); + if (array_key_exists(0, $tmp)) { + $out .= ': ' . $tmp[0]['title']; + } else { + $out .= ': ' . $parameters['row']['value']; + } + $parameters['title'] .= $out; + } + } + } catch (\Exception $e) { + + } + } + +} diff --git a/Classes/User/Tca.php b/Classes/User/Tca.php new file mode 100755 index 0000000..0cae3dc --- /dev/null +++ b/Classes/User/Tca.php @@ -0,0 +1,21 @@ +getQueryParams() ?? []; + if (!isset($queryParams['tx_a2gproducts_a2gproductsdetail']['product'])) { + return ''; + } + $value = $queryParams['tx_a2gproducts_a2gproductsdetail']['product']; + $record = BackendUtility::getRecord('tx_a2gproducts_domain_model_products', $value); + return $record['title']; + } + /** + * @param string + * @param array + * @return string + */ + public function ingredientBreadrumb(string $content, array $conf): string + { + $queryParams = $GLOBALS['TYPO3_REQUEST']->getQueryParams() ?? []; + if (!isset($queryParams['tx_a2gproducts_ingredientsdetail']['ingredient'])) { + return ''; + } + $value = $queryParams['tx_a2gproducts_ingredientsdetail']['ingredient']; + $record = BackendUtility::getRecord('tx_a2gproducts_domain_model_ingredients', $value); + return $record['title']; + } +} \ No newline at end of file diff --git a/Classes/Utility/CanonicalUtility.php b/Classes/Utility/CanonicalUtility.php new file mode 100755 index 0000000..030330d --- /dev/null +++ b/Classes/Utility/CanonicalUtility.php @@ -0,0 +1,68 @@ + 11.x + $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $main = GeneralUtility::_GET(self::$plugin); + if ($main[self::$uidParamName]) { + $uriBuilder = $this->objectManager->get(UriBuilder::class); + $uriBuilder->setCreateAbsoluteUri(true); + $uriBuilder->setArguments([self::$plugin => [self::$uidParamName => $main[self::$uidParamName]]]); + $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class); + $settings = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT); + if (isset($settings['plugin.'][self::$plugin.'.']['settings.']['canonical']) && $settings['plugin.'][self::$plugin.'.']['settings.']['canonical'] !== 0) { + $uriBuilder->setTargetPageUid($settings['plugin.'][self::$plugin.'.']['settings.']['canonical']); + $href = $uriBuilder->build(); + } + } + */ + } +} diff --git a/Classes/ViewHelpers/FilterActiveViewHelper.php b/Classes/ViewHelpers/FilterActiveViewHelper.php new file mode 100755 index 0000000..4239ad1 --- /dev/null +++ b/Classes/ViewHelpers/FilterActiveViewHelper.php @@ -0,0 +1,58 @@ +registerArgument('filter', 'array', 'The cart array', true); + $this->registerArgument('filterUid', 'int', 'The Filter Uid', true); + $this->registerArgument('optionUid', 'int', 'The Filter Option Uid', true); + } + + /** + * @param array $arguments + * @param \Closure $renderChildrenClosure + * @param RenderingContextInterface $renderingContext + * @return mixed + */ + public static function renderStatic( + array $arguments, + \Closure $renderChildrenClosure, + RenderingContextInterface $renderingContext + ) { + if (isset($arguments['filter'][$arguments['filterUid']][$arguments['optionUid']])) { + return 'checked'; + } + return ''; + } + +} diff --git a/Configuration/.htaccess b/Configuration/.htaccess new file mode 100755 index 0000000..896fbc5 --- /dev/null +++ b/Configuration/.htaccess @@ -0,0 +1,2 @@ +Order deny,allow +Deny from all \ No newline at end of file diff --git a/Configuration/Extbase/Persistence/Classes.php b/Configuration/Extbase/Persistence/Classes.php new file mode 100755 index 0000000..ffa85c6 --- /dev/null +++ b/Configuration/Extbase/Persistence/Classes.php @@ -0,0 +1,20 @@ + [ + 'tableName' => 'tx_a2gtoolkit_masonry_item', + 'properties' => [ + 'title' => [ + 'fieldName' => 'title', + ], + 'itemClass' => [ + 'fieldName' => 'item_class', + ], + 'image' => [ + 'fieldName' => 'image', + ], + ], + ] +]; \ No newline at end of file diff --git a/Configuration/FlexForms/flexform_detail.xml b/Configuration/FlexForms/flexform_detail.xml new file mode 100755 index 0000000..f55b7dc --- /dev/null +++ b/Configuration/FlexForms/flexform_detail.xml @@ -0,0 +1,104 @@ + + + + + + Function + + array + + + + + group + db + pages + 1 + 1 + 1 + 1 + + + + + + input + 50 + trim + 0 + + + + + + select + selectMultipleSideBySide + + + tx_a2gproducts_domain_model_categories + + AND (tx_a2gproducts_domain_model_categories.sys_language_uid=CAST('###REC_FIELD_sys_language_uid###' AS UNSIGNED) OR tx_a2gproducts_domain_model_categories.sys_language_uid= '-1') + + 99 + 0 + 10 + + + + + + group + db + pages + 1 + 1 + 0 + 1 + + + + + + select + selectSingle + + + Default + Default + + + StyleOne + StyleOne + + + + + + + + select + selectMultipleSideBySide + + + tx_a2gproducts_domain_model_categories + + AND (tx_a2gproducts_domain_model_categories.sys_language_uid=CAST('###REC_FIELD_sys_language_uid###' AS UNSIGNED) OR tx_a2gproducts_domain_model_categories.sys_language_uid= '-1') + + 99 + 0 + 10 + + + + + + input + 80 + trim + + + + + + + \ No newline at end of file diff --git a/Configuration/FlexForms/flexform_ingredients_detail.xml b/Configuration/FlexForms/flexform_ingredients_detail.xml new file mode 100755 index 0000000..d55b59d --- /dev/null +++ b/Configuration/FlexForms/flexform_ingredients_detail.xml @@ -0,0 +1,64 @@ + + + + + + Function + + array + + + + + group + db + pages + 1 + 1 + 0 + 1 + + + + + + input + 50 + trim + 0 + + + + + + group + db + pages + 1 + 1 + 0 + 1 + + + + + + select + selectSingle + + + A2gProducts + A2gProducts + + + A2gShop + A2gShop + + + + + + + + + \ No newline at end of file diff --git a/Configuration/FlexForms/flexform_ingredients_list.xml b/Configuration/FlexForms/flexform_ingredients_list.xml new file mode 100755 index 0000000..9af846a --- /dev/null +++ b/Configuration/FlexForms/flexform_ingredients_list.xml @@ -0,0 +1,34 @@ + + + + + + Function + + array + + + + + group + db + pages + 1 + 1 + 1 + + + + + + input + 20 + 30 + int,trim + + + + + + + \ No newline at end of file diff --git a/Configuration/FlexForms/flexform_list.xml b/Configuration/FlexForms/flexform_list.xml new file mode 100755 index 0000000..fbfce3c --- /dev/null +++ b/Configuration/FlexForms/flexform_list.xml @@ -0,0 +1,104 @@ + + + + + + Function + + array + + + + + group + db + pages + 1 + 1 + 0 + 1 + + + + + + select + selectSingle + + + A2gProducts + A2gProducts + + + A2gShop + A2gShop + + + + + + + + select + selectMultipleSideBySide + + + tx_a2gproducts_domain_model_categories + + AND (tx_a2gproducts_domain_model_categories.sys_language_uid=CAST('###REC_FIELD_sys_language_uid###' AS UNSIGNED) OR tx_a2gproducts_domain_model_categories.sys_language_uid= '-1') + + 99 + 0 + 10 + + + + + + input + 20 + 30 + int,trim + + + + + + select + selectSingle + + + Product + Product + + + + + + + + select + selectSingle + + + Default + Default + + + StyleOne + StyleOne + + + + + + + + check + + + + + + + \ No newline at end of file diff --git a/Configuration/Services.yml b/Configuration/Services.yml new file mode 100755 index 0000000..911c704 --- /dev/null +++ b/Configuration/Services.yml @@ -0,0 +1,21 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + a2gproducts.cache: + class: TYPO3\CMS\Core\Cache\Frontend\PhpFrontend + # We can not use CacheManager, as it can not be + # injected/instantiated during ext_localconf.php loading + # factory: ['@TYPO3\CMS\Core\Cache\CacheManager', 'getCache'] + # therefore we use the static Bootstrap::createCache factory instead. + factory: ['TYPO3\CMS\Core\Core\Bootstrap', 'createCache'] + arguments: ['products'] + + A2G\A2gProducts\Hreflang\EventListener\ProductsHrefLang: + tags: + - name: event.listener + identifier: 'a2g-products/ProductsHrefLang' + after: 'typo3-seo/hreflangGenerator' + event: TYPO3\CMS\Frontend\Event\ModifyHrefLangTagsEvent \ No newline at end of file diff --git a/Configuration/TCA/Overrides/100_sys_template.php b/Configuration/TCA/Overrides/100_sys_template.php new file mode 100755 index 0000000..c8b45ea --- /dev/null +++ b/Configuration/TCA/Overrides/100_sys_template.php @@ -0,0 +1,30 @@ + 'flexform_list', + 'a2gproducts_a2gproductsdetail' => 'flexform_detail', + 'a2gproducts_ingredientslist' => 'flexform_ingredients_list', + 'a2gproducts_ingredientsdetail' => 'flexform_ingredients_detail' +]; + +foreach ($pluginSignatures as $pluginSignature => $flexform) { + $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist'][$pluginSignature]='pages,layout,select_key,recursive'; + + $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginSignature]='pi_flexform'; + + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue( + $pluginSignature, + 'FILE:EXT:a2g_products/Configuration/FlexForms/'.$flexform.'.xml' + ); +} + +/** + * typo3 12 + * +$pluginSignature = \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( + 'A2gMaps', + 'map', + 'Map' +); +$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginSignature] + = 'pi_flexform'; +ExtensionManagementUtility::addPiFlexFormValue( + $pluginSignature, + 'FILE:EXT:a2g_maps/Configuration/FlexForms/flexform_map.xml' +); +*/ \ No newline at end of file diff --git a/Configuration/TCA/Overrides/500_cropping.php b/Configuration/TCA/Overrides/500_cropping.php new file mode 100755 index 0000000..2ceb957 --- /dev/null +++ b/Configuration/TCA/Overrides/500_cropping.php @@ -0,0 +1,61 @@ + 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:option.default', + 'allowedAspectRatios' => [ + '16:10' => [ + 'title' => '16:10', + 'value' => 16 / 10 + ], + '16:9' => [ + 'title' => 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:ratio.16_9', + 'value' => 16 / 9 + ], + '4:3' => [ + 'title' => 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:ratio.4_3', + 'value' => 4 / 3 + ], + '1:1' => [ + 'title' => 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:ratio.1_1', + 'value' => 1.0 + ], + 'NaN' => [ + 'title' => 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:ratio.free', + 'value' => 0.0 + ], + ], + 'selectedRatio' => 'NaN', + 'cropArea' => [ + 'x' => 0.0, + 'y' => 0.0, + 'width' => 1.0, + 'height' => 1.0, + ] +]; +$largeCropSettings = $defaultCropSettings; +$largeCropSettings['title'] = 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:option.large'; +$mediumCropSettings = $defaultCropSettings; +$mediumCropSettings['title'] = 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:option.medium'; +$smallCropSettings = $defaultCropSettings; +$smallCropSettings['title'] = 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:option.small'; +$extrasmallCropSettings = $defaultCropSettings; +$extrasmallCropSettings['title'] = 'LLL:EXT:bootstrap_package/Resources/Private/Language/Backend.xlf:option.extrasmall'; + +// Content Element Background Image +$GLOBALS['TCA']['tx_a2gproducts_domain_model_ingredients']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['default'] = $defaultCropSettings; +$GLOBALS['TCA']['tx_a2gproducts_domain_model_ingredients']['columns']['images']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['default'] = $defaultCropSettings; + +$GLOBALS['TCA']['tx_a2gproducts_domain_model_products']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['default'] = $defaultCropSettings; +$GLOBALS['TCA']['tx_a2gproducts_domain_model_products']['columns']['images']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['default'] = $defaultCropSettings; + +$GLOBALS['TCA']['tx_a2gproducts_domain_model_productvariants']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['default'] = $defaultCropSettings; +$GLOBALS['TCA']['tx_a2gproducts_domain_model_productvariants']['columns']['images']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['default'] = $defaultCropSettings; + +//$GLOBALS['TCA']['tx_a2gproducts_domain_model_ingredients']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['large'] = $largeCropSettings; +//$GLOBALS['TCA']['tx_a2gproducts_domain_model_ingredients']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['medium'] = $mediumCropSettings; +//$GLOBALS['TCA']['tx_a2gproducts_domain_model_ingredients']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['small'] = $smallCropSettings; +//$GLOBALS['TCA']['tx_a2gproducts_domain_model_ingredients']['columns']['image']['config']['overrideChildTca']['columns']['crop']['config']['cropVariants']['extrasmall'] = $extrasmallCropSettings; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_brands.php b/Configuration/TCA/tx_a2gproducts_domain_model_brands.php new file mode 100755 index 0000000..28e6033 --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_brands.php @@ -0,0 +1,164 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_brands', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'thumbnail' => 'image', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'nr,title', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/brand-image.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, path_segment, image, ' + . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_brands', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_brands}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_brands}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim, required', + 'default' => '' + ], + ], + 'image' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:image', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_categories.php b/Configuration/TCA/tx_a2gproducts_domain_model_categories.php new file mode 100755 index 0000000..d04889e --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_categories.php @@ -0,0 +1,199 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_categories', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'title,description', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/categories.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, rel_filters, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_categories', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_categories}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_categories}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim, required', + 'default' => '' + ], + ], + 'description' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim', + 'default' => '' + ], + ], + 'image' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:image', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'foreign_types' => [ + '0' => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ] + ], + 'foreign_match_fields' => [ + 'fieldname' => 'image', + 'tablenames' => 'tx_a2gproducts_domain_model_categories', + 'table_local' => 'sys_file', + ], + 'maxitems' => 1 + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + + ], + 'rel_filters' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filters', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_filters', + 'foreign_table_where' => ' AND tx_a2gproducts_domain_model_filters.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1) ', + 'MM' => 'tx_a2gproducts_categories_filters_mm', + 'size' => 10, + 'autoSizeMax' => 30, + 'maxitems' => 9999, + 'multiple' => 0, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + + ], + + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_filteroptions.php b/Configuration/TCA/tx_a2gproducts_domain_model_filteroptions.php new file mode 100755 index 0000000..35d44de --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_filteroptions.php @@ -0,0 +1,102 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_filteroptions', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'hideTable' => false, + 'enablecolumns' => [ + 'disabled' => 'hidden' + ], + 'searchFields' => 'title', + 'hideTable' => true, + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/filter-option.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, value_min, value_max'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_filteroptions', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_filteroptions}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_filteroptions}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim', + 'default' => '' + ], + ], + 'value_min' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:value_min', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'double2' + ], + ], + 'value_max' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:value_max', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'double2' + ], + ], + 'filters' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_filters.php b/Configuration/TCA/tx_a2gproducts_domain_model_filters.php new file mode 100755 index 0000000..4a4eae7 --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_filters.php @@ -0,0 +1,180 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_filters', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'type' => 'rel_filter_option', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'title,filter_type', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/filters.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title, filter_type, db_operation_max, db_operation_min, rel_filter_option, --div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_filters', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_filters}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_filters}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim', + 'default' => '' + ], + ], + 'filter_type' => [ + 'exclude' => true, + 'onChange' => 'reload', + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:filter_type', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 3, + 'items' => [ +// [Filters::$dbType[1], 1], +// [Filters::$dbType[2], 2], + ['LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:filter_type.'.Filters::$dbType[3], 3] + ], + ], + ], + 'db_operation_max' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:db_operation_max', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'items' => [ + [Filters::$dbOperations[1], 1], + [Filters::$dbOperations[2], 2], + [Filters::$dbOperations[3], 3], + [Filters::$dbOperations[4], 4], + [Filters::$dbOperations[5], 5] + ], + ], + 'displayCond' => 'FIELD:filter_type:=:1', + ], + 'db_operation_min' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:db_operation_min', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'items' => [ + [Filters::$dbOperations[1], 1], + [Filters::$dbOperations[2], 2], + [Filters::$dbOperations[3], 3], + [Filters::$dbOperations[4], 4], + [Filters::$dbOperations[5], 5] + ], + ], + 'displayCond' => 'FIELD:filter_type:IN:1,2', + ], + 'rel_filter_option' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filter_option', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_filteroptions', + 'foreign_table_where' => 'AND tx_a2gproducts_domain_model_filters.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1)', + 'foreign_field' => 'filters', + 'maxitems' => 9999, + 'appearance' => [ + 'collapseAll' => 1, + 'expandSingle' => 1, + 'levelLinksPosition' => 'top', + 'showSynchronizationLink' => 1, + 'showPossibleLocalizationRecords' => 1, + 'showAllLocalizationLink' => 1 + ], + ], + + ], + + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_filtervalues.php b/Configuration/TCA/tx_a2gproducts_domain_model_filtervalues.php new file mode 100755 index 0000000..3eb83d0 --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_filtervalues.php @@ -0,0 +1,117 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_filtervalues', + 'label' => 'value', + 'label_userFunc' => 'A2G\\A2gProducts\\User\\FilterValuesMatcher->title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'type' => 'rel_filter_option', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'hideTable' => true, + 'enablecolumns' => [ + 'disabled' => 'hidden' + ], + 'searchFields' => '', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/filter-option.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, value,rel_filter_option, rel_filters'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_filtervalues', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_filtervalues}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_filtervalues}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'value' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:value', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'double2' + ], + 'displayCond' => 'USER:A2G\\A2gProducts\\User\\FilterValuesMatcher->showValueInput', + ], + 'rel_filter_option' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filter_option', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_a2gproducts_domain_model_filteroptions', + 'foreign_table_where' => 'AND tx_a2gproducts_domain_model_filteroptions.filters = ###REC_FIELD_rel_filters### AND tx_a2gproducts_domain_model_filteroptions.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1)', + 'default' => 0, + 'minitems' => 0, + 'maxitems' => 1, + ], + 'displayCond' => 'USER:A2G\\A2gProducts\\User\\FilterValuesMatcher->showOptionsSelect', + ], + 'rel_filters' => [ + 'exclude' => true, + 'onChange' => 'reload', + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filters', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_a2gproducts_domain_model_filters', + 'foreign_table_where' => 'AND tx_a2gproducts_domain_model_filters.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1)', + 'default' => 0, + 'minitems' => 0, + 'maxitems' => 1, + ], + ], + 'products' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'productvariants' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_ingredients.php b/Configuration/TCA/tx_a2gproducts_domain_model_ingredients.php new file mode 100755 index 0000000..e75a66f --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_ingredients.php @@ -0,0 +1,308 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_ingredients', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'nr,title,description', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/natural-ingredients.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_diffsource, hidden, title, path_segment, description,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:images_tab, image, images, gallery,' + . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim', + 'default' => '' + ], + ], + 'path_segment' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:slug', + 'config' => [ + 'type' => 'slug', + 'size' => 50, + 'generatorOptions' => [ + 'fields' => ['title'], + 'fieldSeparator' => '/', + 'prefixParentPageSlug' => true, + 'replacements' => [ + '/' => '', + ], + ], + 'fallbackCharacter' => '-', + 'eval' => 'uniqueInSite', + 'default' => '' + ], + ], + 'description' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 15, + 'eval' => 'trim', + 'default' => '' + ] + ], + 'image' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:image', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'images' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:images', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'images', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'minitems' => 0, + 'maxitems' => 10, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'gallery' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_toolkit/Resources/Private/Language/Backend.xlf:masonry_item', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gtoolkit_masonry_item', + 'foreign_field' => 'a2g_ingredients', + 'appearance' => [ + 'useSortable' => true, + 'showSynchronizationLink' => true, + 'showAllLocalizationLink' => true, + 'showPossibleLocalizationRecords' => true, + 'expandSingle' => true, + 'enabledControls' => [ + 'localize' => true, + ] + ], + 'behaviour' => [ + 'mode' => 'select', + ] + ], + ], + 'rel_products' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_products', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_products', + 'foreign_table_where' => ' AND tx_a2gproducts_domain_model_products.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1) AND tx_a2gproducts_domain_model_products.pid=###CURRENT_PID### ', + 'MM' => 'tx_a2gproducts_products_ingredients_mm', + 'MM_opposite_field' => 'uid_foreign', + 'size' => 10, + 'autoSizeMax' => 30, + 'maxitems' => 20, + 'multiple' => 0, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + ], + 'rel_productvariants' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_productvariants', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_productvariants', + 'foreign_table_where' => ' AND tx_a2gproducts_domain_model_productvariants.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1) AND tx_a2gproducts_domain_model_productvariants.pid=###CURRENT_PID### ', + 'MM' => 'tx_a2gproducts_products_productvariants_mm', + 'MM_opposite_field' => 'uid_foreign', + 'size' => 10, + 'autoSizeMax' => 30, + 'maxitems' => 20, + 'multiple' => 0, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_products.php b/Configuration/TCA/tx_a2gproducts_domain_model_products.php new file mode 100755 index 0000000..b9565cc --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_products.php @@ -0,0 +1,599 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_products', + 'label' => 'title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'descriptionColumn' => 'description', + 'thumbnail' => 'image', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'nr,title,description', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/package.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, nr, title, path_segment, rel_category, description, description_html, rel_brand,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:images_tab, image, images,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:ingredients_tab, rel_ingredients,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:filters_tab, rel_filter_values, ' +// . '--div--;Product Attributes, rel_selectableattribute, ' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:product_variants_tab, rel_productvariants, ' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_tab, seo_image1x1,seo_image4x3,seo_image16x9,' + . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_products', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_products}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_products}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'nr' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:product_nr', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim, required', + 'default' => '' + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim, required', + 'default' => '' + ], + ], + 'path_segment' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:slug', + 'config' => [ + 'type' => 'slug', + 'size' => 50, + 'generatorOptions' => [ + 'fields' => ['title'], + 'fieldSeparator' => '/', + 'prefixParentPageSlug' => true, + 'replacements' => [ + '/' => '', + ], + ], + 'fallbackCharacter' => '-', + 'eval' => 'uniqueInSite', + 'default' => '' + ], + ], + 'description' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 15, + 'eval' => 'trim', + 'default' => '' + ] + ], + 'description_html' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description_html', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 15, + 'eval' => 'trim', + 'enableRichtext' => true, + 'default' => '' + ] + ], + 'image' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:image', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'images' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:images', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'images', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'minitems' => 0, + 'maxitems' => 10, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'gallery' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_toolkit/Resources/Private/Language/Backend.xlf:masonry_item', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gtoolkit_masonry_item', + 'foreign_field' => 'a2g_products', + 'appearance' => [ + 'useSortable' => true, + 'showSynchronizationLink' => true, + 'showAllLocalizationLink' => true, + 'showPossibleLocalizationRecords' => true, + 'expandSingle' => true, + 'enabledControls' => [ + 'localize' => true, + ] + ], + 'behaviour' => [ + 'mode' => 'select', + ] + ], + ], + 'seo_image1x1' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_image1x1', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'foreign_match_fields' => [ + 'fieldname' => 'seo_image1x1', + 'tablenames' => 'tx_a2gproducts_domain_model_products', + 'table_local' => 'sys_file', + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'seo_image4x3' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_image4x3', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'foreign_match_fields' => [ + 'fieldname' => 'seo_image4x3', + 'tablenames' => 'tx_a2gproducts_domain_model_products', + 'table_local' => 'sys_file', + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'seo_image16x9' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_image16x9', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'foreign_match_fields' => [ + 'fieldname' => 'seo_image16x9', + 'tablenames' => 'tx_a2gproducts_domain_model_products', + 'table_local' => 'sys_file', + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'rel_category' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_category', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_categories', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_categories}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) AND {#tx_a2gproducts_domain_model_categories}.{#pid}=###CURRENT_PID### ', + 'MM' => 'tx_a2gproducts_products_categories_mm', + 'size' => 10, + 'autoSizeMax' => 30, + 'maxitems' => 20, + 'multiple' => false, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + ], + 'rel_filter_values' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filter_values', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_filtervalues', + 'foreign_field' => 'products', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_filtervalues}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) ', + 'maxitems' => 20, + 'appearance' => [ + 'collapseAll' => 0, + 'levelLinksPosition' => 'top', + 'showSynchronizationLink' => 1, + 'showPossibleLocalizationRecords' => 1, + 'showAllLocalizationLink' => 1 + ], + ], + ], + 'rel_selectableattribute' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_selectableattribute', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_selectableattribute', + 'foreign_field' => 'products', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_selectableattribute}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) ', + 'maxitems' => 20, + 'appearance' => [ + 'collapseAll' => 0, + 'levelLinksPosition' => 'top', + 'showSynchronizationLink' => 1, + 'showPossibleLocalizationRecords' => 1, + 'showAllLocalizationLink' => 1 + ], + ], + ], + 'rel_ingredients' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_ingredients', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_ingredients', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_ingredients}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) AND {#tx_a2gproducts_domain_model_ingredients}.{#pid}=###CURRENT_PID### ', + 'MM' => 'tx_a2gproducts_products_ingredients_mm', + 'size' => 10, + 'autoSizeMax' => 30, + 'minitems' => 0, + 'maxitems' => 20, + 'multiple' => 1, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + ], + 'rel_productvariants' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_productvariants', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_productvariants', + 'foreign_table_where' => ' AND tx_a2gproducts_domain_model_productvariants.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1) AND tx_a2gproducts_domain_model_productvariants.pid=###CURRENT_PID### ', + 'foreign_field' => 'product', + 'size' => 10, + 'autoSizeMax' => 30, + 'foreign_sortby' => 'sorting', + 'minitems' => 1, + 'maxitems' => 20, + 'appearance' => [ + 'collapseAll' => 1, + 'expandSingle' => 1, + ], + ], + ], + 'rel_brand' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_brand', + 'config' => [ + 'type' => 'group', + 'internal_type' => 'db', + 'allowed' => 'tx_a2gproducts_domain_model_brands', + 'maxitems' => 1, + 'minitems' => 0, + 'size' => 1, + 'default' => 0, + 'suggestOptions' => [ + 'default' => [ + 'additionalSearchFields' => 'title', + 'addWhere' => 'AND tx_a2gproducts_domain_model_brands.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1) AND tx_a2gproducts_domain_model_brands.pid=###CURRENT_PID###' + ] + ], + ], + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_productvariants.php b/Configuration/TCA/tx_a2gproducts_domain_model_productvariants.php new file mode 100755 index 0000000..b67af83 --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_productvariants.php @@ -0,0 +1,665 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_productvariants', + 'label' => 'title', + 'label_userFunc' => \A2G\A2gProducts\User\Tca::class . '->productVariantTitle', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'nr,title,description', + 'hideTable' => true, + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/fingerprint-outline-variant.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden,product, nr, title, path_segment, description, description_html,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:images_tab, tab_icon, image, images,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:ingredients_tab, rel_ingredients,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:filters_tab, rel_category, rel_filter_values, ' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:selectabel_product_attribute_tab, rel_selectableattribute, ' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_tab, seo_image1x1,seo_image4x3,seo_image16x9,' + . '--div--;LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:sizes_tab, rel_sizes,' + . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_productvariants', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_productvariants}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_productvariants}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'nr' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:product_nr', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim, required', + 'default' => '' + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim', + 'default' => '' + ], + ], + 'path_segment' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:slug', + 'config' => [ + 'type' => 'slug', + 'size' => 50, + 'generatorOptions' => [ + 'fields' => ['title'], + 'fieldSeparator' => '/', + 'prefixParentPageSlug' => true, + 'replacements' => [ + '/' => '', + ], + ], + 'fallbackCharacter' => '-', + 'default' => '' + ], + ], + 'description' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 15, + 'eval' => 'trim', + 'default' => '' + ] + ], + 'description_html' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description_html', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 15, + 'eval' => 'trim', + 'enableRichtext' => true, + 'default' => '' + ] + ], + 'tab_icon' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tab_icon', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'tab_icon', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'maxitems' => 1 + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'image' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:image', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'maxitems' => 1 + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'images' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:images', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'images', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'maxitems' => 10 + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'gallery' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:gallery', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'images', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'foreign_types' => [ + '0' => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette, + --palette--;;filePalette' + ] + ], + 'foreign_match_fields' => [ + 'fieldname' => 'gallery', + 'tablenames' => 'tx_a2gproducts_domain_model_productvariants', + 'table_local' => 'sys_file', + ], + 'maxitems' => 20 + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'seo_image1x1' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_image1x1', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'foreign_match_fields' => [ + 'fieldname' => 'seo_image1x1', + 'tablenames' => 'tx_a2gproducts_domain_model_products', + 'table_local' => 'sys_file', + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'seo_image4x3' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_image4x3', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'foreign_match_fields' => [ + 'fieldname' => 'seo_image4x3', + 'tablenames' => 'tx_a2gproducts_domain_model_products', + 'table_local' => 'sys_file', + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'seo_image16x9' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:seo_image16x9', + 'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig( + 'image', + [ + 'appearance' => [ + 'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference' + ], + 'overrideChildTca' => [ + 'types' => [ + \TYPO3\CMS\Core\Resource\File::FILETYPE_UNKNOWN => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [ + 'showitem' => ' + title, + description, + alternative, + crop, + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + \TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [ + 'showitem' => ' + --palette--;;filePalette + ' + ], + ], + ], + 'foreign_match_fields' => [ + 'fieldname' => 'seo_image16x9', + 'tablenames' => 'tx_a2gproducts_domain_model_products', + 'table_local' => 'sys_file', + ], + 'minitems' => 0, + 'maxitems' => 1, + ], + $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] + ), + ], + 'rel_category' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_category', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_categories', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_categories}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) AND {#tx_a2gproducts_domain_model_categories}.{#pid}=###CURRENT_PID### ', + 'MM' => 'tx_a2gproducts_productvariants_categories_mm', + 'size' => 10, + 'autoSizeMax' => 30, + 'maxitems' => 20, + 'multiple' => 1, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + ], + 'rel_filter_values' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filter_values', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_filtervalues', + 'foreign_field' => 'productvariants', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_filtervalues}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) ', + 'maxitems' => 20, + 'appearance' => [ + 'collapseAll' => 0, + 'levelLinksPosition' => 'top', + 'showSynchronizationLink' => 1, + 'showPossibleLocalizationRecords' => 1, + 'showAllLocalizationLink' => 1 + ], + ], + ], + 'rel_selectableattribute' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_selectableattribute', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_selectableattribute', + 'foreign_field' => 'productvariants', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_selectableattribute}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) ', + 'maxitems' => 20, + 'appearance' => [ + 'collapseAll' => 0, + 'levelLinksPosition' => 'top', + 'showSynchronizationLink' => 1, + 'showPossibleLocalizationRecords' => 1, + 'showAllLocalizationLink' => 1 + ], + ], + ], + 'rel_ingredients' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_ingredients', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectMultipleSideBySide', + 'foreign_table' => 'tx_a2gproducts_domain_model_ingredients', + 'foreign_table_where' => ' AND {#tx_a2gproducts_domain_model_ingredients}.{#sys_language_uid} IN (###REC_FIELD_sys_language_uid###,-1) AND {#tx_a2gproducts_domain_model_ingredients}.{#pid}=###CURRENT_PID### ', + 'MM' => 'tx_a2gproducts_ingredients_productvariants_mm', + 'size' => 10, + 'autoSizeMax' => 30, + 'minitems' => 0, + 'maxitems' => 20, + 'multiple' => 1, + 'fieldControl' => [ + 'editPopup' => [ + 'disabled' => false, + ], + 'addRecord' => [ + 'disabled' => false, + ], + 'listModule' => [ + 'disabled' => true, + ], + ], + ], + ], + 'product' => [ + 'config' => array( + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_a2gproducts_domain_model_products', + ), + ], + 'rel_sizes' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_sizes', + 'config' => [ + 'type' => 'inline', + 'foreign_table' => 'tx_a2gproducts_domain_model_productvariantsizes', + 'foreign_table_where' => ' AND tx_a2gproducts_domain_model_productvariantsizes.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1) AND tx_a2gproducts_domain_model_productvariantsizes.pid=###CURRENT_PID### ', + 'foreign_field' => 'productvariant', + 'size' => 10, + 'autoSizeMax' => 30, + 'foreign_sortby' => 'sorting', + 'minitems' => 0, + 'maxitems' => 30, + 'appearance' => [ + 'collapseAll' => 1, + 'expandSingle' => 1, + ], + ], + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_productvariantsizes.php b/Configuration/TCA/tx_a2gproducts_domain_model_productvariantsizes.php new file mode 100755 index 0000000..9776ffa --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_productvariantsizes.php @@ -0,0 +1,158 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_productvariantsizes', + 'label' => 'title', +// 'label_userFunc' => \A2G\A2gProducts\User\Tca::class . '->productVariantTitle', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'sortby' => 'sorting', + 'cruser_id' => 'cruser_id', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'delete' => 'deleted', + 'enablecolumns' => [ + 'disabled' => 'hidden', + 'starttime' => 'starttime', + 'endtime' => 'endtime', + ], + 'searchFields' => 'nr,title,description', + 'hideTable' => true, + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/fingerprint-outline-variant.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, nr, title, path_segment, description,' + . '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.access, starttime, endtime'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_productvariantsizes', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_productvariantsizes}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_productvariantsizes}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'starttime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.starttime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'endtime' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.endtime', + 'config' => [ + 'type' => 'input', + 'renderType' => 'inputDateTime', + 'eval' => 'datetime,int', + 'default' => 0, + 'range' => [ + 'upper' => mktime(0, 0, 0, 1, 1, 2038) + ], + 'behaviour' => [ + 'allowLanguageSynchronization' => true + ] + ], + ], + 'nr' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:product_nr', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim, required', + 'default' => '' + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim', + 'default' => '' + ], + ], + 'path_segment' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:slug', + 'config' => [ + 'type' => 'slug', + 'size' => 50, + 'generatorOptions' => [ + 'fields' => ['title'], + 'fieldSeparator' => '/', + 'prefixParentPageSlug' => true, + 'replacements' => [ + '/' => '', + ], + ], + 'fallbackCharacter' => '-', + 'default' => '' + ], + ], + 'description' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:description', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 15, + 'eval' => 'trim', + 'default' => '' + ] + ], + 'productvariant' => [ + 'config' => array( + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_a2gproducts_domain_model_productvariants', + ), + ], + ], +]; diff --git a/Configuration/TCA/tx_a2gproducts_domain_model_selectableattribute.php b/Configuration/TCA/tx_a2gproducts_domain_model_selectableattribute.php new file mode 100755 index 0000000..400ce7b --- /dev/null +++ b/Configuration/TCA/tx_a2gproducts_domain_model_selectableattribute.php @@ -0,0 +1,116 @@ + [ + 'title' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2gproducts_domain_model_selectableattribute', + 'label' => 'title', + 'label_userFunc' => 'A2G\\A2gProducts\\User\\FilterValuesMatcher->title', + 'tstamp' => 'tstamp', + 'crdate' => 'crdate', + 'cruser_id' => 'cruser_id', + 'type' => 'rel_filter_option', + 'versioningWS' => true, + 'languageField' => 'sys_language_uid', + 'transOrigPointerField' => 'l10n_parent', + 'transOrigDiffSourceField' => 'l10n_diffsource', + 'hideTable' => true, + 'enablecolumns' => [ + 'disabled' => 'hidden' + ], + 'searchFields' => '', + 'iconfile' => 'EXT:a2g_products/Resources/Public/Icons/tag.png' + ], + 'types' => [ + '1' => ['showitem' => 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, title,rel_filter_option, rel_filters'], + ], + 'columns' => [ + 'sys_language_uid' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language', + 'config' => [ + 'type' => 'language' + ], + ], + 'l10n_parent' => [ + 'displayCond' => 'FIELD:sys_language_uid:>:0', + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'default' => 0, + 'items' => [ + ['', 0], + ], + 'foreign_table' => 'tx_a2gproducts_domain_model_selectableattribute', + 'foreign_table_where' => 'AND {#tx_a2gproducts_domain_model_selectableattribute}.{#pid}=###CURRENT_PID### AND {#tx_a2gproducts_domain_model_selectableattribute}.{#sys_language_uid} IN (-1,0)', + ], + ], + 'l10n_diffsource' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'hidden' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.visible', + 'config' => [ + 'type' => 'check', + 'renderType' => 'checkboxToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'invertStateDisplay' => true + ] + ], + ], + ], + 'title' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:title', + 'config' => [ + 'type' => 'input', + 'size' => 30, + 'eval' => 'trim' + ] + ], + 'rel_filter_option' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filter_option', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_a2gproducts_domain_model_filteroptions', + 'foreign_table_where' => 'AND tx_a2gproducts_domain_model_filteroptions.filters = ###REC_FIELD_rel_filters### AND tx_a2gproducts_domain_model_filteroptions.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1)', + 'default' => 0, + 'minitems' => 0, + 'maxitems' => 1, + ], + 'displayCond' => 'USER:A2G\\A2gProducts\\User\\FilterValuesMatcher->showOptionsSelect', + ], + 'rel_filters' => [ + 'exclude' => true, + 'onChange' => 'reload', + 'label' => 'LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:rel_filters', + 'config' => [ + 'type' => 'select', + 'renderType' => 'selectSingle', + 'foreign_table' => 'tx_a2gproducts_domain_model_filters', + 'foreign_table_where' => 'AND tx_a2gproducts_domain_model_filters.filter_type = 3 AND tx_a2gproducts_domain_model_filters.sys_language_uid IN (###REC_FIELD_sys_language_uid###,-1)', + 'default' => 0, + 'minitems' => 0, + 'maxitems' => 1, + ], + ], + 'products' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + 'productvariants' => [ + 'config' => [ + 'type' => 'passthrough', + ], + ], + ], +]; diff --git a/Configuration/TsConfig/Page/All.tsconfig b/Configuration/TsConfig/Page/All.tsconfig new file mode 100755 index 0000000..ab2fac8 --- /dev/null +++ b/Configuration/TsConfig/Page/All.tsconfig @@ -0,0 +1,4 @@ +################## +#### TsConfig #### +################## + diff --git a/Configuration/TsConfig/Page/Wizards.tsconfig b/Configuration/TsConfig/Page/Wizards.tsconfig new file mode 100755 index 0000000..d956912 --- /dev/null +++ b/Configuration/TsConfig/Page/Wizards.tsconfig @@ -0,0 +1,46 @@ +################################ +#### CONTENT ELEMENT WIZARD #### +################################ +mod.wizards.newContentElement.wizardItems.a2gProducts { + after = common, menu, special, forms, plugins + header = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:wizard.group.products + elements { + a2gproductslist { + iconIdentifier = a2g_products-plugin-a2gproductslist + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductslist.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductslist.description + tt_content_defValues { + CType = list + list_type = a2gproducts_a2gproductslist + } + } + a2gproductsdetail { + iconIdentifier = a2g_products-plugin-a2gproductsdetail + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductsdetail.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductsdetail.description + tt_content_defValues { + CType = list + list_type = a2gproducts_a2gproductsdetail + } + } + ingredientslist { + iconIdentifier = a2g_products-plugin-ingredientslist + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientslist.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientslist.description + tt_content_defValues { + CType = list + list_type = a2gproducts_ingredientslist + } + } + ingredientsdetail { + iconIdentifier = a2g_products-plugin-ingredientsdetail + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientsdetail.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientsdetail.description + tt_content_defValues { + CType = list + list_type = a2gproducts_ingredientsdetail + } + } + } + show = * +} diff --git a/Configuration/TypoScript/Base/constants.typoscript b/Configuration/TypoScript/Base/constants.typoscript new file mode 100755 index 0000000..21498be --- /dev/null +++ b/Configuration/TypoScript/Base/constants.typoscript @@ -0,0 +1,14 @@ +plugin.tx_a2gproducts_a2gproducts { + view { + # cat=altogether products/file; type=string; label=Path to template root (FE) + templateRootPath = EXT:a2g_products/Resources/Private/Templates/ + # cat=altogether products/file; type=string; label=Path to template partials (FE) + partialRootPath = EXT:a2g_products/Resources/Private/Partials/ + # cat=altogether products/file; type=string; label=Path to template layouts (FE) + layoutRootPath = EXT:a2g_products/Resources/Private/Layouts/ + } + persistence { + # cat=altogether products//a; type=string; label=Default storage PID + storagePid = + } +} \ No newline at end of file diff --git a/Configuration/TypoScript/Base/setup.typoscript b/Configuration/TypoScript/Base/setup.typoscript new file mode 100755 index 0000000..d0452b7 --- /dev/null +++ b/Configuration/TypoScript/Base/setup.typoscript @@ -0,0 +1,115 @@ +plugin.tx_a2gproducts_a2gproductslist { + view { + templateRootPaths.0 = EXT:a2g_products/Resources/Private/Templates/ + templateRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.templateRootPath} + partialRootPaths.0 = EXT:a2g_products/Resources/Private/Partials/ + partialRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.partialRootPath} + layoutRootPaths.0 = EXT:a2g_products/Resources/Private/Layouts/ + layoutRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.layoutRootPath} + } + persistence { + storagePid = {$plugin.tx_a2gproducts_a2gproductslist.persistence.storagePid} + #recursive = 1 + } +} +plugin.tx_a2gproducts_a2gproductsdetail { + view { + templateRootPaths.0 = EXT:a2g_products/Resources/Private/Templates/ + templateRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.templateRootPath} + partialRootPaths.0 = EXT:a2g_products/Resources/Private/Partials/ + partialRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.partialRootPath} + layoutRootPaths.0 = EXT:a2g_products/Resources/Private/Layouts/ + layoutRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.layoutRootPath} + } + persistence { + storagePid = {$plugin.tx_a2gproducts_a2gproductsdetail.persistence.storagePid} + #recursive = 1 + } +} +plugin.tx_a2gproducts_ingredientslist { + view { + templateRootPaths.0 = EXT:a2g_products/Resources/Private/Templates/ + templateRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.templateRootPath} + partialRootPaths.0 = EXT:a2g_products/Resources/Private/Partials/ + partialRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.partialRootPath} + layoutRootPaths.0 = EXT:a2g_products/Resources/Private/Layouts/ + layoutRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.layoutRootPath} + } + persistence { + storagePid = {$plugin.tx_a2gproducts_a2gproducts.persistence.storagePid} + #recursive = 1 + } +} +plugin.tx_a2gproducts_ingredientsdetail { + view { + templateRootPaths.0 = EXT:a2g_products/Resources/Private/Templates/ + templateRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.templateRootPath} + partialRootPaths.0 = EXT:a2g_products/Resources/Private/Partials/ + partialRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.partialRootPath} + layoutRootPaths.0 = EXT:a2g_products/Resources/Private/Layouts/ + layoutRootPaths.1 = {$plugin.tx_a2gproducts_a2gproducts.view.layoutRootPath} + } + persistence { + storagePid = {$plugin.tx_a2gproducts_a2gproducts.persistence.storagePid} + #recursive = 1 + } +} + +page.includeJSFooter.rslider = EXT:a2g_products/Resources/Public/JavaScript/rSlider.min.js +page.includeJSFooter.rslider { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.a2gProductsList = EXT:a2g_products/Resources/Public/JavaScript/a2gProductsList.js +page.includeJSFooter.a2gProductsList { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.a2gProductsSwiperInit = EXT:a2g_products/Resources/Public/JavaScript/a2gProductsSwiper.init.js +page.includeJSFooter.a2gProductsSwiperInit { + disableCompression = 0 + excludeFromConcatenation = 0 +} + +page.includeCSS { + rslider = EXT:a2g_products/Resources/Public/Scss/rSlider.min.scss + a2gProductsList = EXT:a2g_products/Resources/Public/Scss/a2gProductsList.scss +} + +a2gProductList = PAGE +a2gProductList { + typeNum = 1629140329 + config { + disableAllHeaderCode = 1 + admPanel = 0 + additionalHeaders.10.header = Content-type:text/html + xhtml_cleaning = 0 + debug = 0 + no_cache = 1 + } + 10 = USER + 10 { + userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run + extensionName = A2gProducts + pluginName = A2gproductslist + vendorName = Altogether + controller = Products + settings < plugin.tx_a2gproducts_a2gproductslist.settings + persistence < plugin.tx_a2gproducts_a2gproductslist.persistence + view < plugin.tx_a2gproducts_a2gproductslist.view + } +} + +config.pageTitleProviders { + product { + provider = A2G\A2gProducts\PageTitle\A2gPageTitleProvider + before = seo + } + seo { + provider = TYPO3\CMS\Seo\PageTitle\SeoTitlePageTitleProvider + before = record + } +} + + + \ No newline at end of file diff --git a/Configuration/TypoScript/Breadcrumb/setup.typoscript b/Configuration/TypoScript/Breadcrumb/setup.typoscript new file mode 100755 index 0000000..22f9c83 --- /dev/null +++ b/Configuration/TypoScript/Breadcrumb/setup.typoscript @@ -0,0 +1,41 @@ +[traverse(request.getQueryParams(), 'tx_a2gproducts_a2gproductsdetail/product') > 0] +page { + 10 { + variables { + breadcrumbExtendedValue = COA + breadcrumbExtendedValue { + 10 = USER + 10 { + userFunc = A2G\A2gProducts\User\TypoScript->productBreadrumb + } + } + } + dataProcessing { + 30 { + special.range = 0|-2 + } + } + } +} +[end] + +[traverse(request.getQueryParams(), 'tx_a2gproducts_ingredientsdetail/ingredient') > 0] +page { + 10 { + variables { + breadcrumbExtendedValue = COA + breadcrumbExtendedValue { + 10 = USER + 10 { + userFunc = A2G\A2gProducts\User\TypoScript->ingredientBreadrumb + } + } + } + dataProcessing { + 30 { + special.range = 0|-2 + } + } + } +} +[end] diff --git a/Configuration/TypoScript/Canonical/setup.typoscript b/Configuration/TypoScript/Canonical/setup.typoscript new file mode 100755 index 0000000..0865232 --- /dev/null +++ b/Configuration/TypoScript/Canonical/setup.typoscript @@ -0,0 +1,48 @@ +[traverse(request.getQueryParams(), 'tx_a2gproducts_a2gproductsdetail/product') > 0] + page.headerData.20 = TEXT + page.headerData.20 { + typolink { + # hol die aktuelle Page Id + parameter.data = page:uid + # prüfe ob die Id wirklich eine Zahl ist + parameter.intval = 1 + useCacheHash = 1 + # füge zur URL alle Parameter hinzu + additionalParams.cObject = COA + additionalParams.cObject { + 10 = TEXT + 10.dataWrap = &tx_a2gproducts_a2gproductsdetail[product]={GP:tx_a2gproducts_a2gproductsdetail|product} + 10.if.isTrue.data = GP:tx_a2gproducts_a2gproductsdetail|product + } + forceAbsoluteUrl = 1 + returnLast = url + } + # bau mir den Meta-Tag zusammen + wrap = + } +[global] + + +[traverse(request.getQueryParams(), 'tx_a2gproducts_ingredientsdetail/ingredient') > 0] + page.headerData.20 = TEXT + page.headerData.20 { + typolink { + # hol die aktuelle Page Id + parameter.data = page:uid + # prüfe ob die Id wirklich eine Zahl ist + parameter.intval = 1 + useCacheHash = 1 + # füge zur URL alle Parameter hinzu + additionalParams.cObject = COA + additionalParams.cObject { + 10 = TEXT + 10.dataWrap = &tx_a2gproducts_ingredientsdetail[ingredient]={GP:tx_a2gproducts_ingredientsdetail|ingredient} + 10.if.isTrue.data = GP:tx_a2gproducts_ingredientsdetail|ingredient + } + forceAbsoluteUrl = 1 + returnLast = url + } + # bau mir den Meta-Tag zusammen + wrap = + } +[global] diff --git a/Configuration/TypoScript/GoogleAnalytics/constants.typoscript b/Configuration/TypoScript/GoogleAnalytics/constants.typoscript new file mode 100755 index 0000000..e69de29 diff --git a/Configuration/TypoScript/GoogleAnalytics/setup.typoscript b/Configuration/TypoScript/GoogleAnalytics/setup.typoscript new file mode 100755 index 0000000..0391b7a --- /dev/null +++ b/Configuration/TypoScript/GoogleAnalytics/setup.typoscript @@ -0,0 +1,46 @@ +page.includeJSFooter.gaCheckout = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.js +page.includeJSFooter.gaCheckout { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaProduct = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProduct.js +page.includeJSFooter.gaProduct { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaProducts = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProducts.js +page.includeJSFooter.gaProducts { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaPromotion = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotion.js +page.includeJSFooter.gaPromotion { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaPromotions = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.js +page.includeJSFooter.gaPromotions { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaPurchase = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPurchase.js +page.includeJSFooter.gaPurchase { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaRefund = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefund.js +page.includeJSFooter.gaRefund { + disableCompression = 0 + excludeFromConcatenation = 0 +} +page.includeJSFooter.gaRefunds = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.js +page.includeJSFooter.gaRefunds { + disableCompression = 0 + excludeFromConcatenation = 0 +} + +page.includeJSFooter.gaEcommerce = EXT:a2g_products/Resources/Public/JavaScript/GoogleAnalytics/A2gGaEcommerce.js +page.includeJSFooter.gaEcommerce { + disableCompression = 1 + excludeFromConcatenation = 1 +} diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript new file mode 100755 index 0000000..09ab258 --- /dev/null +++ b/Configuration/TypoScript/constants.typoscript @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript new file mode 100755 index 0000000..87a6b79 --- /dev/null +++ b/Configuration/TypoScript/setup.typoscript @@ -0,0 +1,3 @@ + + + diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..2071b23 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..0f24995 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# a2g_products + diff --git a/Resources/Private/.htaccess b/Resources/Private/.htaccess new file mode 100755 index 0000000..96d0729 --- /dev/null +++ b/Resources/Private/.htaccess @@ -0,0 +1,11 @@ +# Apache < 2.3 + + Order allow,deny + Deny from all + Satisfy All + + +# Apache >= 2.3 + + Require all denied + diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf new file mode 100755 index 0000000..be6ff3a --- /dev/null +++ b/Resources/Private/Language/de.locallang.xlf @@ -0,0 +1,36 @@ + + + +
+ + + detail + mehr erfahren + + + article nr + Artikel Nr + + + search + suchen + + + advanced search + erweiterte Suche + + + search + suche + + + related products + Produkte mit dieser Zutat + + + used ingredients + Verwendete Zutaten + + + + diff --git a/Resources/Private/Language/de.locallang_csh_tx_a2gproducts_domain_model_products.xlf b/Resources/Private/Language/de.locallang_csh_tx_a2gproducts_domain_model_products.xlf new file mode 100755 index 0000000..8e06c7b --- /dev/null +++ b/Resources/Private/Language/de.locallang_csh_tx_a2gproducts_domain_model_products.xlf @@ -0,0 +1,63 @@ + + + +
+ + + product nr + Produkt Nr + + + product title <br/> +for Search Engin Optimation ( SEO ) and link preview ( <a href="https://ogp.me/">open graph</a> ) + Produkt Titel / Name <br/> +für Suchmaschinenoptimierung ( SEO ) und Link-Vorschau ( <a href="https://ogp.me/">open graph</a> ) + + + description <br/> +for Search Engin Optimation ( SEO ) and link preview ( <a href="https://ogp.me/">open graph</a> ) + Produkt Beschreibung <br/> +für Suchmaschinenoptimierung ( SEO ) und Link-Vorschau ( <a href="https://ogp.me/">open graph</a> ) + + + product list image <br/> +for Search Engin Optimation ( SEO ) and link preview ( <a href="https://ogp.me/">open graph</a> ) + Produkt Listen Bild <br/> +für Suchmaschinenoptimierung ( SEO ) und Link-Vorschau ( <a href="https://ogp.me/">open graph</a> ) + + + images + Produkt Detail Seiten Bild Slider + + + relCategory + Produkt Kategorie ( Verwendet für Filter ) + + + relFilterValues + Filterbare Optionen +von dem FIlter aus der Kategorie + + + url segment generated from the product title + URL Segment generiert aus dem Produk-Titel + + + farmateable description + Formatierbare Beschreibung unter der Beschreibung + + + ingredients + Verwendete Inhaltsstoffe, Bauteile oder Zutaten + + + + + + + deliverycosts conditions per each product + Liefergebühren abzüge zuschläge pro Produkt + + + + diff --git a/Resources/Private/Language/de.locallang_db.xlf b/Resources/Private/Language/de.locallang_db.xlf new file mode 100755 index 0000000..b85255a --- /dev/null +++ b/Resources/Private/Language/de.locallang_db.xlf @@ -0,0 +1,308 @@ + + + +
+ + + Brands + Marken / Kollektionen + + + Products + Produkte + + + Products + Produkte + + + Nr + + + + Title + Titel + + + Description + Beschreibung + + + Image + Bild + + + Images + Bilder + + + Net Price + Netto Preis + + + Gross Price + Brutto Preis + + + Category + Kategorie + + + Filter Values + Filter Werte + + + Categories + Kategorien + + + Title + Titel + + + Description + Beschreibung + + + Image + Bild + + + Filters + Filter + + + Filters + Filter + + + Title + Titel + + + Filter Type + Filter Typ + + + Db Operation Max + Db Operation Max + + + Db Operation Min + Db Operation Min + + + Filter Option + Filter Option + + + Filter Options + Filter Optionen + + + Title + Titel + + + Value Min + min. Wert + + + Value Max + max. Wert + + + Filter Values + Filter Werte + + + Value + Wert + + + Filters + Filter + + + Altogether Products - Product List + Altogether Produkte - Produktliste + + + + Liste der Produkte mit filter und such Möglichkeit. + + + Altogether Products - Product Detail + Altogether Produkte - Produkt Detail Seite + + + + Detailseite eines Produktes + + + Altogether Products - Ingredients List + Altogether Produkte - Liste der Inhaltsstoffe + + + + + + + Altogether Products - Ingredients Detail + Altogether Produkte - Inhaltsstoffe Detail Seite + + + + + + + Ingredients + Inhaltstoffe + + + title + Titel + + + description + Beschreibung + + + image + Bild + + + Filters + Filter + + + min value + min. Wert + + + max value + max. Wert + + + filter type + Filter Typ + + + operation min + min. Operant + + + operation max + max. Operant + + + filter option + Filter Optionen + + + value + Wert + + + images + Bilder + + + products + Produkte + + + product nr + Produkt Nr. + + + category + Kateogie + + + filter values + Filter Werte + + + ingredients + Inhaltsstoffe + + + used ingredients + verwendete Zutaten + + + products with this ingredient + Produkte mit dieser Zutat + + + just use Filter Options + Filteroptionen verwenden + + + slug + Url Segment + + + Images + Bilder + + + Varainats + Varianten + + + Filters + Filter + + + Ingredients + Inhaltsstoffe + + + Sizes + Größen + + + Product-Variants + Produkt Varianten + + + Description ( RTE ) + Beschreibung ( RTE ) + + + Product Options + Produkt Optionen + + + Selectable Produkt Options + Wählbare Produkt Optionen + + + Brand + Marke + + + Brands + Marken + + + SEO Image 1x1 + + + + SEO Image 4x3 + + + + SEO Image 16x9 + + + + SEO + + + + + \ No newline at end of file diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf new file mode 100755 index 0000000..6cf8b21 --- /dev/null +++ b/Resources/Private/Language/locallang.xlf @@ -0,0 +1,29 @@ + + + +
+ + + detail + + + article nr + + + search + + + advanced search + + + search + + + related products + + + used ingredients + + + + diff --git a/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_categories.xlf b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_categories.xlf new file mode 100755 index 0000000..b79f22c --- /dev/null +++ b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_categories.xlf @@ -0,0 +1,20 @@ + + + +
+ + + title + + + description + + + image + + + relFilters + + + + diff --git a/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filteroptions.xlf b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filteroptions.xlf new file mode 100755 index 0000000..cdb69df --- /dev/null +++ b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filteroptions.xlf @@ -0,0 +1,17 @@ + + + +
+ + + title + + + valueMin + + + valueMax + + + + diff --git a/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filters.xlf b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filters.xlf new file mode 100755 index 0000000..80ea8af --- /dev/null +++ b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filters.xlf @@ -0,0 +1,23 @@ + + + +
+ + + title + + + filterType + + + dbOperationMax + + + dbOperationMin + + + relFilterOption + + + + diff --git a/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filtervalues.xlf b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filtervalues.xlf new file mode 100755 index 0000000..ad010ad --- /dev/null +++ b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_filtervalues.xlf @@ -0,0 +1,14 @@ + + + +
+ + + value + + + relFilters + + + + diff --git a/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_products.xlf b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_products.xlf new file mode 100755 index 0000000..7de6d7d --- /dev/null +++ b/Resources/Private/Language/locallang_csh_tx_a2gproducts_domain_model_products.xlf @@ -0,0 +1,47 @@ + + + +
+ + + product nr + + + product title <br/> +for Search Engin Optimation ( SEO ) and link preview ( <a href="https://ogp.me/">open graph</a> ) + + + description <br/> +for Search Engin Optimation ( SEO ) and link preview ( <a href="https://ogp.me/">open graph</a> ) + + + product list image <br/> +for Search Engin Optimation ( SEO ) and link preview ( <a href="https://ogp.me/">open graph</a> ) + + + images + + + relCategory + + + relFilterValues + + + url segment generated from the product title + + + farmateable description + + + ingredients + + + + + + deliverycosts conditions per each product + + + + diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf new file mode 100755 index 0000000..efa1036 --- /dev/null +++ b/Resources/Private/Language/locallang_db.xlf @@ -0,0 +1,221 @@ + + + +
+ + + Brands + + + Products + + + Products + + + Nr + + + Title + + + Description + + + Image + + + Images + + + Net Price + + + Gross Price + + + Category + + + Filter Values + + + Categories + + + Title + + + Description + + + Image + + + Filters + + + Filters + + + Title + + + Filter Type + + + Db Operation Max + + + Db Operation Min + + + Filter Option + + + Filter Options + + + Title + + + Value Min + + + Value Max + + + Filter Values + + + Value + + + Filters + + + Altogether Products - Product List + + + + + + Altogether Products - Product Detail + + + + + + Altogether Products - Ingredients List + + + + + + Altogether Products - Ingredients Detail + + + + + + Ingredients + + + title + + + description + + + image + + + Filters + + + min value + + + max value + + + filter type + + + operation min + + + operation max + + + filter option + + + value + + + images + + + products + + + product nr + + + category + + + filter values + + + ingredients + + + used ingredients + + + products with this ingredient + + + just use Filter Options + + + slug + + + Images + + + SEO + + + Sizes + + + Varainats + + + Filters + + + Ingredients + + + Product-Variants + + + Description ( RTE ) + + + Product Options + + + Selectable Produkt Options + + + Tab Icon + + + + diff --git a/Resources/Private/Layouts/Ajax.html b/Resources/Private/Layouts/Ajax.html new file mode 100755 index 0000000..211755d --- /dev/null +++ b/Resources/Private/Layouts/Ajax.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Resources/Private/Layouts/Default.html b/Resources/Private/Layouts/Default.html new file mode 100755 index 0000000..64e85e9 --- /dev/null +++ b/Resources/Private/Layouts/Default.html @@ -0,0 +1,5 @@ + +
+ +
+ diff --git a/Resources/Private/Partials/ContentElements/Masonry.html b/Resources/Private/Partials/ContentElements/Masonry.html new file mode 100755 index 0000000..07c41e9 --- /dev/null +++ b/Resources/Private/Partials/ContentElements/Masonry.html @@ -0,0 +1,54 @@ + + + +
+ + +
+
+ + + + + + + + + + + 300 + + + 350 + + + 650 + + + 970 + + + 1280 + + + {item.image.data.width} + + + a2g-{item.image.properties.alternative} + + + +
+
+
+
+ diff --git a/Resources/Private/Partials/Default/AjaxList.html b/Resources/Private/Partials/Default/AjaxList.html new file mode 100755 index 0000000..4061f5d --- /dev/null +++ b/Resources/Private/Partials/Default/AjaxList.html @@ -0,0 +1,2 @@ + + diff --git a/Resources/Private/Partials/Default/List.html b/Resources/Private/Partials/Default/List.html new file mode 100755 index 0000000..fa83376 --- /dev/null +++ b/Resources/Private/Partials/Default/List.html @@ -0,0 +1,12 @@ + +
+
+ +
+
+
+ +
+
+
+ diff --git a/Resources/Private/Partials/Default/Products/List/Filter.html b/Resources/Private/Partials/Default/Products/List/Filter.html new file mode 100755 index 0000000..b8aacf6 --- /dev/null +++ b/Resources/Private/Partials/Default/Products/List/Filter.html @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + +
+
+ + +
+ +
+
+
+
+
+
+ + + +
+ diff --git a/Resources/Private/Partials/Default/Products/List/List.html b/Resources/Private/Partials/Default/Products/List/List.html new file mode 100755 index 0000000..eb9f819 --- /dev/null +++ b/Resources/Private/Partials/Default/Products/List/List.html @@ -0,0 +1,24 @@ + + + + + + + +
+ +
+
+
+
+ + + + + +
+ + + +
+ \ No newline at end of file diff --git a/Resources/Private/Partials/Default/Products/Properties.html b/Resources/Private/Partials/Default/Products/Properties.html new file mode 100755 index 0000000..2783c36 --- /dev/null +++ b/Resources/Private/Partials/Default/Products/Properties.html @@ -0,0 +1,58 @@ + + + {_all} + + +

{product.title}

+ : {product.nr} +
+ +
+ + + + + +
+
+ +
+
+ diff --git a/Resources/Private/Partials/Default/Show.html b/Resources/Private/Partials/Default/Show.html new file mode 100755 index 0000000..3acb47e --- /dev/null +++ b/Resources/Private/Partials/Default/Show.html @@ -0,0 +1,42 @@ + + +

Single View for Products

+ + + + + + Back to list + diff --git a/Resources/Private/Partials/FilterElements/Checkbox.html b/Resources/Private/Partials/FilterElements/Checkbox.html new file mode 100755 index 0000000..e6fe818 --- /dev/null +++ b/Resources/Private/Partials/FilterElements/Checkbox.html @@ -0,0 +1,20 @@ + +
+
+ {filter.title} +
+
+ +
+ + +
+
+
+
+ diff --git a/Resources/Private/Partials/FilterElements/FilterGroups.html b/Resources/Private/Partials/FilterElements/FilterGroups.html new file mode 100755 index 0000000..5ff967c --- /dev/null +++ b/Resources/Private/Partials/FilterElements/FilterGroups.html @@ -0,0 +1,46 @@ + + + + + + + + + + +
+
+ +
+
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + +
+ diff --git a/Resources/Private/Partials/FilterElements/RangeSlider.html b/Resources/Private/Partials/FilterElements/RangeSlider.html new file mode 100755 index 0000000..c627c24 --- /dev/null +++ b/Resources/Private/Partials/FilterElements/RangeSlider.html @@ -0,0 +1,16 @@ + + + + + TODO supply a title + + + + +
TODO write content
+ + diff --git a/Resources/Private/Partials/FilterElements/Selectbox.html b/Resources/Private/Partials/FilterElements/Selectbox.html new file mode 100755 index 0000000..c627c24 --- /dev/null +++ b/Resources/Private/Partials/FilterElements/Selectbox.html @@ -0,0 +1,16 @@ + + + + + TODO supply a title + + + + +
TODO write content
+ + diff --git a/Resources/Private/Partials/Image.html b/Resources/Private/Partials/Image.html new file mode 100755 index 0000000..044695f --- /dev/null +++ b/Resources/Private/Partials/Image.html @@ -0,0 +1,80 @@ + + + + {variant.breakpoint as integer} + {variant.width as integer} + + + + {variant.aspectRatio as float} + {width / aspectRatio} + {height as integer} + + {f:if(condition: breakpoint, then: 'media="(min-width: {breakpoint}px)"')} + + + + {sizeConfig.multiplier as float} + {sizeWidth * width} + + + + {sizeConfig.multiplier as float} + {sizeHeight * height} + {f:uri.image(image: file, cropVariant: name, width: '{sizeWidth}c', height: '{sizeHeight}c',absolute:'true')} + + + + + {f:uri.image(image: file, cropVariant: 'default', width: maxWidth, absolute:'true')} + + + {f:uri.image(image: file, cropVariant: 'default', width: sizeWidth, absolute:'true')} + + + + + {srcset}{sizeUrl} {sizeKey}{f:if(condition: iteration.isLast, else: ',')} + + + f:format.raw()} srcset="{srcset}"> + + + + + + {defaultAspectRatio as float} + {defaultWidth / aspectRatio} + {defaultHeight as integer}c + + + + + + + + + + + + + + + + + + + + + + + + + {file.properties.alternative} + + + {file.properties.alternative} + + + + diff --git a/Resources/Private/Partials/ListElements/CardContent.html b/Resources/Private/Partials/ListElements/CardContent.html new file mode 100755 index 0000000..1de7414 --- /dev/null +++ b/Resources/Private/Partials/ListElements/CardContent.html @@ -0,0 +1,42 @@ + +
+ + + +
+ +
+
+
+
+
+
{product.title}
+

+ + {product.description} + +

+
+
    + +
  • + {values.relFilters.title} : + + + {values.relFilterOption.title} + + + {values.value} + + +
  • +
    +
+
+ + + +
+
+ + \ No newline at end of file diff --git a/Resources/Private/Partials/ListElements/Ingredients.html b/Resources/Private/Partials/ListElements/Ingredients.html new file mode 100755 index 0000000..8a3d374 --- /dev/null +++ b/Resources/Private/Partials/ListElements/Ingredients.html @@ -0,0 +1,24 @@ + +
+
+ + +
+ +
+
+
+
{ingredient.title}
+

+ + {ingredient.description} + +

+
+ +
+ diff --git a/Resources/Private/Partials/ListElements/LoadMoreButton.html b/Resources/Private/Partials/ListElements/LoadMoreButton.html new file mode 100755 index 0000000..a32318f --- /dev/null +++ b/Resources/Private/Partials/ListElements/LoadMoreButton.html @@ -0,0 +1,7 @@ + +
+ +
+ \ No newline at end of file diff --git a/Resources/Private/Partials/ListElements/NoProductFound.html b/Resources/Private/Partials/ListElements/NoProductFound.html new file mode 100755 index 0000000..29b439d --- /dev/null +++ b/Resources/Private/Partials/ListElements/NoProductFound.html @@ -0,0 +1,5 @@ + +
+ no product found +
+ \ No newline at end of file diff --git a/Resources/Private/Partials/Slider/Images.html b/Resources/Private/Partials/Slider/Images.html new file mode 100755 index 0000000..40572fe --- /dev/null +++ b/Resources/Private/Partials/Slider/Images.html @@ -0,0 +1,22 @@ + +
+
+ +
+ {image.alt} +
+
+
+
+
+
+
+
+ +
+ {image.alt} +
+
+
+
+ diff --git a/Resources/Private/Partials/Slider/Ingredients.html b/Resources/Private/Partials/Slider/Ingredients.html new file mode 100755 index 0000000..d8a3bfd --- /dev/null +++ b/Resources/Private/Partials/Slider/Ingredients.html @@ -0,0 +1,23 @@ + + + + + +
+
+ +
+
+
+
+
+
+ +
+ +
+
+
+
+
+ \ No newline at end of file diff --git a/Resources/Private/Partials/Slider/Products.html b/Resources/Private/Partials/Slider/Products.html new file mode 100755 index 0000000..8e3ce27 --- /dev/null +++ b/Resources/Private/Partials/Slider/Products.html @@ -0,0 +1,22 @@ + + + + +
+
+ +
+
+
+
+
+
+ +
+ +
+
+
+
+
+ diff --git a/Resources/Private/Partials/StyleOne/AjaxList.html b/Resources/Private/Partials/StyleOne/AjaxList.html new file mode 100755 index 0000000..4061f5d --- /dev/null +++ b/Resources/Private/Partials/StyleOne/AjaxList.html @@ -0,0 +1,2 @@ + + diff --git a/Resources/Private/Partials/StyleOne/List.html b/Resources/Private/Partials/StyleOne/List.html new file mode 100755 index 0000000..c962f45 --- /dev/null +++ b/Resources/Private/Partials/StyleOne/List.html @@ -0,0 +1,6 @@ + + +
+ +
+ diff --git a/Resources/Private/Partials/StyleOne/Products/List/Filter.html b/Resources/Private/Partials/StyleOne/Products/List/Filter.html new file mode 100755 index 0000000..23b5d14 --- /dev/null +++ b/Resources/Private/Partials/StyleOne/Products/List/Filter.html @@ -0,0 +1,48 @@ + + + + + + + + + + + +
+
+ + +
+
+ +
+
+ +
+
+ + +
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + + +
+ diff --git a/Resources/Private/Partials/StyleOne/Products/List/List.html b/Resources/Private/Partials/StyleOne/Products/List/List.html new file mode 100755 index 0000000..1ba1ffa --- /dev/null +++ b/Resources/Private/Partials/StyleOne/Products/List/List.html @@ -0,0 +1,23 @@ + + + + + + +
+ +
+
+
+
+ + + + + +
+ + + +
+ \ No newline at end of file diff --git a/Resources/Private/Partials/StyleOne/Products/Properties.html b/Resources/Private/Partials/StyleOne/Products/Properties.html new file mode 100755 index 0000000..c8ee948 --- /dev/null +++ b/Resources/Private/Partials/StyleOne/Products/Properties.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + {products.nr} +
+ + + {products.title} +
+ + + {products.description} +
+ + + + + + + + +
+ + + + + + + +
+ + + {products.price} +
+ + +
+ +
+ {values.relFilters.title} : + + + {values.relFilterOption.title} + + + {values.value} + + +
+
+
+{products} + diff --git a/Resources/Private/Partials/StyleOne/Show.html b/Resources/Private/Partials/StyleOne/Show.html new file mode 100755 index 0000000..4910b52 --- /dev/null +++ b/Resources/Private/Partials/StyleOne/Show.html @@ -0,0 +1,51 @@ + +

Single View for Products

+ + + + + + + Back to list
+ New Products + diff --git a/Resources/Private/Templates/Ingredients/List.html b/Resources/Private/Templates/Ingredients/List.html new file mode 100755 index 0000000..27c7f48 --- /dev/null +++ b/Resources/Private/Templates/Ingredients/List.html @@ -0,0 +1,13 @@ + + + + +
+ +
+ +
+
+
+
+ diff --git a/Resources/Private/Templates/Ingredients/Show.html b/Resources/Private/Templates/Ingredients/Show.html new file mode 100755 index 0000000..3be20da --- /dev/null +++ b/Resources/Private/Templates/Ingredients/Show.html @@ -0,0 +1,87 @@ + + + + +

{ingredient.title}

+
+ + + +
+
+ {ingredient.title} +
+
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+ + + +
+
+ +
+
+
+ +
+ + + + + +
+
+
+
+
+
+

+ {ingredient.description} +

+
+ +
+ + +
+

+
+ +
+ diff --git a/Resources/Private/Templates/Products/AjaxList.html b/Resources/Private/Templates/Products/AjaxList.html new file mode 100755 index 0000000..930edf7 --- /dev/null +++ b/Resources/Private/Templates/Products/AjaxList.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Resources/Private/Templates/Products/List.html b/Resources/Private/Templates/Products/List.html new file mode 100755 index 0000000..2d3d948 --- /dev/null +++ b/Resources/Private/Templates/Products/List.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/Resources/Private/Templates/Products/Show.html b/Resources/Private/Templates/Products/Show.html new file mode 100755 index 0000000..03c39d6 --- /dev/null +++ b/Resources/Private/Templates/Products/Show.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/Resources/Public/Icons/Extension.png b/Resources/Public/Icons/Extension.png new file mode 100755 index 0000000000000000000000000000000000000000..a190977e5c72c784351d7968ce329eee94002641 GIT binary patch literal 47066 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 literal 0 HcmV?d00001 diff --git a/Resources/Public/Icons/brand-image.png b/Resources/Public/Icons/brand-image.png new file mode 100755 index 0000000000000000000000000000000000000000..2feec39ff59d88da2bbf4a9c3dbe384fecbcb3bd GIT binary patch literal 3895 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 literal 0 HcmV?d00001 diff --git a/Resources/Public/Icons/filters.png b/Resources/Public/Icons/filters.png new file mode 100755 index 0000000000000000000000000000000000000000..25f15e11a645ed2c94d640c76112a6eff70b7613 GIT binary patch literal 2140 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 literal 0 HcmV?d00001 diff --git a/Resources/Public/Icons/natural-ingredients.png b/Resources/Public/Icons/natural-ingredients.png new file mode 100755 index 0000000000000000000000000000000000000000..1acc5c4cbff95782eef46c52969b6ff33186bc22 GIT binary patch literal 21211 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 literal 0 HcmV?d00001 diff --git a/Resources/Public/Icons/package.png b/Resources/Public/Icons/package.png new file mode 100755 index 0000000000000000000000000000000000000000..cb0f007a7c6ad9e0c7b052bdf1d9c170861f4c91 GIT binary patch literal 2219 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 XPI^MhXsK7$00000NkvXXu0mjf-l~8) literal 0 HcmV?d00001 diff --git a/Resources/Public/JavaScript/GoogleAnalytics/A2gGaEcommerce.js b/Resources/Public/JavaScript/GoogleAnalytics/A2gGaEcommerce.js new file mode 100755 index 0000000..b158f52 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/A2gGaEcommerce.js @@ -0,0 +1,17 @@ +/** + * A2gGaEcommerce + */ +var A2gGaEcommerce = function () { + 'use strict'; + var Constructor = function () { + +// id, name, price = 0.0, quantity = 0, currency = '', categories = [], listId = 'all_products', listName = 'All Products', position= 0, brand = '', variant = '', locationId = '', affiliation = 'altogether store', discount = 0.0, coupon = '') { + +// GaProduct test +var gaProduct = new GaProduct('test_id', 'test_name', 323.23, 3, 'EUR', ['category1', 'category2'], 'all_products', 'All Products', 1, 'test brand', 'test variant', '', 'altogether store'); +gaProduct.selectItem(); + +console.log(gaProduct); + }; + return Constructor; +}(GaCheckout, GaProduct, GaProducts, GaPromotion, GaPromotions, GaPurchase, GaRefund, GaRefunds) diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.js new file mode 100755 index 0000000..034dcc4 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.js @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 Raphael Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaCheckout + */ +var GaCheckout = function () { + 'use strict'; + var Constructor = function () { + }; + Constructor.prototype.checkout = function (step, option, GaProductsObject, url) { + if (typeof ga === 'function' && typeof dataLayer === 'object' && typeof GaProductsObject === 'object' && GaProductsObject instanceof GaProducts) { + var products = []; + for (var i = 0; i < GaProductsObject.arr.length; i++) { + products.push({ + 'name': GaProductsObject.arr[i].name, // Name or ID is required. + 'id': GaProductsObject.arr[i].id, + 'price': GaProductsObject.arr[i].price, + 'brand': GaProductsObject.arr[i].brand, + 'category': GaProductsObject.arr[i].category, + 'variant': GaProductsObject.arr[i].variant, + 'quantity': GaProductsObject.arr[i].quantity + }); + } + dataLayer.push({ + 'event': 'checkout', + 'ecommerce': { + 'checkout': { + 'actionField': {'step': step, 'option': option}, + 'products': products + } + }, + 'eventCallback': function(){ + document.location = url; + } + }); + } else { + console.log('GaCheckout.checkout requiers ga and dataLayer'); + } + }; + Constructor.prototype.checkoutOption = function (step, option) { + if (typeof ga === 'function' && typeof dataLayer === 'object') { + dataLayer.push({ + 'event': 'checkoutOption', + 'ecommerce': { + 'checkout': { + 'actionField': {'step': step, 'option': option} + } + } + }); + } else { +// console.log('checkoutOption requiers ga and dataLayer'); + } + }; + return Constructor; +}(); + + diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.min.js new file mode 100755 index 0000000..28aa364 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaCheckout.min.js @@ -0,0 +1 @@ +var GaCheckout=function(){"use strict";var t=function(){};return t.prototype.checkout=function(t,e,a,o){if("function"==typeof ga&&"object"==typeof dataLayer&&"object"==typeof a&&a instanceof GaProducts){for(var r=[],c=0;c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaProduct + */ +var GaProduct = function () { + 'use strict'; + var Constructor = function (id, name, price = 0.0, quantity = 0, currency = '', categories = [], listId = 'all_products', listName = 'All Products', position = 0, brand = '', variant = '', locationId = '', affiliation = 'altogether store', discount = 0.0, coupon = '') { + if (typeof ga === 'function' && typeof dataLayer === 'object' && typeof gtag === 'function') { + this.item_id = id; + this.item_name = name; + for (var i = 0; i < categories.length; i++) { + if (i === 0) { + this.item_category = categories[i]; + } + if (i === 1) { + this.item_category2 = categories[i]; + } + if (i === 2) { + this.item_category3 = categories[i]; + } + if (i === 3) { + this.item_category4 = categories[i]; + } + if (i === 4) { + this.item_category5 = categories[i]; + } + } + if (price > 0) { + this.price = price; + } + if (currency !== '') { + this.currency = currency; + } + if (quantity > 0) { + this.quantity = quantity; + } + if (position > 0) { + this.index = position; + } + if (brand !== '') { + this.item_brand = brand; + } + if (variant !== '') { + this.item_variant = variant; + } + if (listId !== '') { + this.item_list_id = listId; + } + if (listName !== '') { + this.item_list_name = listName; + } + if (locationId !== '') { + this.location_id = locationId; + } + if (affiliation !== '') { + this.affiliation = affiliation; + } + if (discount > 0.00) { + this.discount = discount; + } + if (coupon !== '') { + this.coupon = coupon; + } + } else { + console.log('ga datalayer or gtag missing'); + } + }; + Constructor.prototype.selectItem = function () { + gtag('event', 'select_item', { + item_list_id: this.listId, + item_list_name: this.listName, + items: [JSON.stringify(this)] + }); + }; + Constructor.prototype.viewItem = function () { + gtag('event', 'view_item', { + currency: this.currency, + value: this.price, + items: [JSON.stringify(this)] + }); + }; + Constructor.prototype.addToCart = function (currencyCode = 'EUR') { + if (typeof ga === 'function' && typeof dataLayer === 'object') { + dataLayer.push({ + 'event': 'addToCart', + 'ecommerce': { + 'currencyCode': currencyCode.toUpperCase(), + 'add': { + 'products': [{ + 'name': this.name, // Name or ID is required. + 'id': this.id, + 'price': this.price, + 'brand': this.brand, + 'category': this.category, + 'variant': this.variant, + 'position': this.position + }] + } + } + }); + } else { +// console.log('GaProduct.addToCart requiers ga and dataLayer'); + } + }; + Constructor.prototype.removeFromCart = function () { + if (typeof ga === 'function' && typeof dataLayer === 'object') { + dataLayer.push({ + 'event': 'removeFromCart', + 'ecommerce': { + 'remove': { + 'products': [{ + 'name': this.name, // Name or ID is required. + 'id': this.id, + 'price': this.price, + 'brand': this.brand, + 'category': this.category, + 'variant': this.variant, + 'position': this.position + }] + } + } + }); + } else { +// console.log('GaProduct.removeFromCart requiers ga and dataLayer'); + } + }; + return Constructor; +}(); diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProduct.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProduct.min.js new file mode 100755 index 0000000..f95d9ca --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProduct.min.js @@ -0,0 +1 @@ +function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var GaProduct=function(){"use strict";function t(t,e,i,o,a,n){var r=6 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaProducts + */ +var GaProducts = function () { + 'use strict'; + var Constructor = function (itemListId, itemListName, GaProductObject) { + this.item_list_id = itemListId; + this.item_list_name = itemListName; + this.arr = []; + if (typeof (GaProductObject) === 'object' && GaProductObject instanceof GaProduct) { + this.arr.push(GaProductObject); + } + }; + Constructor.prototype.push = function (GaProductObject) { + if (typeof (GaProductObject) === 'object' && GaProductObject instanceof GaProduct) { + this.arr.push(GaProductObject); + } else { + console.log('GaProductObject must be a instanceof GaProduct'); + } + }; + Constructor.prototype.viewItemList = function () { + gtag("event", "view_item_list", { + item_list_id: this.item_list_id, + item_list_name: this.item_list_name, + items: JSON.stringify(this.arr) + }); + }; + Constructor.prototype.impressions = function (currencyCode = 'EUR', list = 'Search Results') { + if (typeof ga === 'function' && typeof dataLayer === 'object' && this.arr.length > 0) { + var products = []; + for (var i = 0; i < this.arr.length; i++) { + products.push({ + 'name': this.arr[i].name, // Name or ID is required. + 'id': this.arr[i].id, + 'price': this.arr[i].price, + 'brand': this.arr[i].brand, + 'category': this.arr[i].category, + 'variant': this.arr[i].variant, + 'list': list, + 'position': this.arr[i].position + }); + } + dataLayer.push({ + 'ecommerce': { + 'currencyCode': currencyCode, + 'impressions': products + } + }); + } else { + console.log('GaProducts.productClick requiers ga and dataLayer'); + } + }; + Constructor.prototype.addToCart = function (currencyCode = 'EUR') { + if (typeof ga === 'function' && typeof dataLayer === 'object' && this.arr.length > 0) { + var products = []; + for (var i = 0; i < this.arr.length; i++) { + products.push({ + 'name': this.arr[i].name, // Name or ID is required. + 'id': this.arr[i].id, + 'price': this.arr[i].price, + 'brand': this.arr[i].brand, + 'category': this.arr[i].category, + 'variant': this.arr[i].variant, + 'quantity': this.arr[i].quantity + }); + } + dataLayer.push({ + 'event': 'addToCart', + 'ecommerce': { + 'currencyCode': currencyCode.toUpperCase(), + 'add': { + 'products': products + } + } + }); + } else { + console.log('GaProducts.addToCart requiers ga and dataLayer'); + } + }; + Constructor.prototype.removeFromCart = function () { + if (typeof ga === 'function' && typeof dataLayer === 'object' && this.arr.length > 0) { + var products = []; + for (var i = 0; i < this.arr.length; i++) { + products.push({ + 'name': this.arr[i].name, // Name or ID is required. + 'id': this.arr[i].id, + 'price': this.arr[i].price, + 'brand': this.arr[i].brand, + 'category': this.arr[i].category, + 'variant': this.arr[i].variant, + 'quantity': this.arr[i].quantity + }); + } + dataLayer.push({ + 'event': 'removeFromCart', + 'ecommerce': { + 'remove': { + 'products': products + } + } + }); + } else { + console.log('GaProducts.removeFromCart requiers ga and dataLayer'); + } + }; + return Constructor; +}(GaProduct); diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProducts.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProducts.min.js new file mode 100755 index 0000000..9a98e1b --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaProducts.min.js @@ -0,0 +1 @@ +function _typeof(r){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(r){return typeof r}:function(r){return r&&"function"==typeof Symbol&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r})(r)}var GaProducts=function(){"use strict";function r(r){this.arr=[],"object"===_typeof(r)&&r instanceof GaProduct?this.arr.push(r):console.log("GaProductObject must be a instanceof GaProduct")}return r.prototype.push=function(r){"object"===_typeof(r)&&r instanceof GaProduct?this.arr.push(r):console.log("GaProductObject must be a instanceof GaProduct")},r.prototype.impressions=function(){var r=0 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaPromotion + */ +var GaPromotion = function () { + 'use strict'; + var Constructor = function (id, name, creative, position) { + this.id = id; + this.name = name; + this.creative = creative; + this.position = position; + }; + Constructor.prototype.promotionClick = function (url) { + if (typeof ga === 'function' && typeof dataLayer === 'object') { + var promotions = []; + promotions.push({ + 'id': this.id, // Name or ID is required. + 'name': this.name, + 'creative': this.creative, + 'position': this.position + }); + dataLayer.push({ + 'event': 'promotionClick', + 'ecommerce': { + 'promoClick': { + 'promotions': promotions + } + }, + 'eventCallback': function(){ + document.location = url; + } + }); + } else { +// console.log('GaPromotion.promotionClick requiers ga and dataLayer'); + } + }; + return Constructor; +}(); diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotion.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotion.min.js new file mode 100755 index 0000000..6c46864 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotion.min.js @@ -0,0 +1 @@ +function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var GaPromotion=function(){"use strict";function t(t,o,e,n){this.id=t,this.name=o,this.creative=e,this.position=n}return t.prototype.promotionClick=function(t){var o;"function"==typeof ga&&"object"===("undefined"==typeof dataLayer?"undefined":_typeof(dataLayer))&&((o=[]).push({id:this.id,name:this.name,creative:this.creative,position:this.position}),dataLayer.push({event:"promotionClick",ecommerce:{promoClick:{promotions:o}},eventCallback:function(){document.location=t}}))},t}(); \ No newline at end of file diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.js new file mode 100755 index 0000000..9d4408e --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.js @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2021 Raphael Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaPromotions + */ +var GaPromotions = function () { + 'use strict'; + var Constructor = function (GaPromotionObject) { + this.arr = []; + if (typeof (GaPromotionObject) === 'object' && GaPromotionObject instanceof GaPromotion) { + this.arr.push(GaPromotionObject); + } else { + console.log('GaPromotionObject must be a instanceof GaPromotion'); + } + }; + Constructor.prototype.push = function (GaProductObject) { + if (typeof (GaProductObject) === 'object' && GaProductObject instanceof GaProduct) { + this.arr.push(GaProductObject); + } else { + console.log('GaProductObject must be a instanceof GaProduct'); + } + }; + Constructor.prototype.promoView = function () { + if (typeof ga === 'function' && typeof dataLayer === 'object' && this.arr.length > 0) { + var promotions = []; + for (var i = 0; i < this.arr.length; i++) { + promotions.push({ + 'id': this.arr[i].id, // Name or ID is required. + 'name': this.arr[i].name, + 'creative': this.arr[i].creative, + 'position': this.arr[i].position + }); + } + dataLayer.push({ + 'ecommerce': { + 'promoView': { + 'promotions': promotions + } + } + }); + } else { +// console.log('GaPromotions.promoView requiers ga and dataLayer'); + } + }; + return Constructor; +}(GaPromotion); diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.min.js new file mode 100755 index 0000000..cdd5ce5 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPromotions.min.js @@ -0,0 +1 @@ +function _typeof(o){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o})(o)}var GaPromotions=function(){"use strict";function o(o){this.arr=[],"object"===_typeof(o)&&o instanceof GaPromotion?this.arr.push(o):console.log("GaPromotionObject must be a instanceof GaPromotion")}return o.prototype.push=function(o){"object"===_typeof(o)&&o instanceof GaProduct?this.arr.push(o):console.log("GaProductObject must be a instanceof GaProduct")},o.prototype.promoView=function(){if("function"==typeof ga&&"object"===("undefined"==typeof dataLayer?"undefined":_typeof(dataLayer))&&0 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaPurchase + */ +var GaPurchase = function () { + 'use strict'; + var Constructor = function (id, affiliation, revenue, tax, shipping, coupon) { + this.id = id; + this.affiliation = affiliation; + this.revenue = revenue; + this.tax = tax; + this.shipping = shipping; + this.coupon = coupon; + }; + Constructor.prototype.purchase = function (GaProductsObject) { + if (typeof ga === 'function' && typeof dataLayer === 'object' && typeof GaProductsObject === 'object' && GaProductsObject instanceof GaProducts) { + var products = []; + for (var i = 0; i < GaProductsObject.arr.length; i++) { + products.push({ + 'name': GaProductsObject.arr[i].name, // Name or ID is required. + 'id': GaProductsObject.arr[i].id, + 'price': GaProductsObject.arr[i].price, + 'brand': GaProductsObject.arr[i].brand, + 'category': GaProductsObject.arr[i].category, + 'variant': GaProductsObject.arr[i].variant, + 'quantity': GaProductsObject.arr[i].quantity + }); + } + dataLayer.push({ + 'event': 'checkout', + 'ecommerce': { + 'purchase': { + 'actionField': { + 'id': this.id, // Transaction ID. Required for purchases and refunds. + 'affiliation': this.affiliation, + 'revenue': this.revenue, // Total transaction value (incl. tax and shipping) + 'tax': this.tax, + 'shipping': this.shipping, + 'coupon': this.coupon + }, + 'products': products + } + } + }); + } else { +// console.log('GaPurchase.purchase requiers ga and dataLayer'); + } + }; + return Constructor; +}(GaProducts); \ No newline at end of file diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPurchase.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPurchase.min.js new file mode 100755 index 0000000..ca96f95 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaPurchase.min.js @@ -0,0 +1 @@ +function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var GaPurchase=function(){"use strict";function t(t,e,i,o,r,n){this.id=t,this.affiliation=e,this.revenue=i,this.tax=o,this.shipping=r,this.coupon=n}return t.prototype.purchase=function(t){if("function"==typeof ga&&"object"===("undefined"==typeof dataLayer?"undefined":_typeof(dataLayer))&&"object"===_typeof(t)&&t instanceof GaProducts){for(var e=[],i=0;i + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaRefund + */ +var GaRefund = function () { + 'use strict'; + var Constructor = function (id) { + this.id = id; + }; + Constructor.prototype.refund = function () { + if (typeof ga === 'function' && typeof dataLayer === 'object') { + dataLayer.push({ + 'event': 'checkout', + 'ecommerce': { + 'refund': { + 'actionField': { + 'id': this.id + } + } + } + }); + } else { +// console.log('GaRefund.refund requiers ga and dataLayer'); + } + }; + return Constructor; +}(); \ No newline at end of file diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefund.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefund.min.js new file mode 100755 index 0000000..6f9c40d --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefund.min.js @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Raphael Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaRefund + */ +var GaRefund = function () { + 'use strict'; + var Constructor = function (id) { + this.id = id; + }; + Constructor.prototype.refund = function () { + if (typeof ga === 'function' && typeof dataLayer === 'object') { + dataLayer.push({ + 'event': 'checkout', + 'ecommerce': { + 'refund': { + 'actionField': { + 'id': this.id + } + } + } + }); + } else { +// console.log('GaRefund.refund requiers ga and dataLayer'); + } + }; + return Constructor; +}(); \ No newline at end of file diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.js new file mode 100755 index 0000000..71322e9 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.js @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Raphael Martin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** + * GaRefunds + */ +var GaRefunds = function () { + 'use strict'; + var Constructor = function (gaRefundObject) { + + if (typeof (gaRefundObject) === 'object' && gaRefundObject instanceof GaRefund) { + this.gaRefund = gaRefundObject; + } else { + console.log('GaProductObject must be a instanceof GaProduct'); + } + }; + Constructor.prototype.refund = function (GaProductsObject) { + if (typeof ga === 'function' && typeof dataLayer === 'object' && typeof GaProductsObject === 'object' && GaProductsObject instanceof GaProducts) { + var products = []; + for (var i = 0; i < GaProductsObject.arr.length; i++) { + products.push({ + 'id': GaProductsObject.arr[i].id, + 'quantity': GaProductsObject.arr[i].quantity + }); + } + dataLayer.push({ + 'event': 'checkout', + 'ecommerce': { + 'refund': { + 'actionField': { + 'id': this.gaRefund.id + }, + 'products': products + } + } + }); + } else { +// console.log('GaRefunds.refund requiers ga and dataLayer'); + } + }; + return Constructor; +}(GaProducts, GaRefund); \ No newline at end of file diff --git a/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.min.js b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.min.js new file mode 100755 index 0000000..b4d00e3 --- /dev/null +++ b/Resources/Public/JavaScript/GoogleAnalytics/google-analytics/GaRefunds.min.js @@ -0,0 +1 @@ +var GaRefunds=function(){"use strict";var t=function(t){"object"==typeof t&&t instanceof GaRefund?this.gaRefund=t:console.log("GaProductObject must be a instanceof GaProduct")};return t.prototype.refund=function(t){if("function"==typeof ga&&"object"==typeof dataLayer&&"object"==typeof t&&t instanceof GaProducts){for(var e=[],a=0;a= 0 && matches.item(i) !== el) { + } + ; + } while ((i < 0) && (el = el.parentElement)); + return el; + }; +} + +var a2gProductsList = { + wrapClass: 'altogether-products', + filterInputClass: 'a2g-filter-input', + ajaxFormClass: 'a2g-ajax-form', + ajaxContentClass: 'a2g-ajax-content', + ajaxLoadMoreInputClass: 'a2g-ajax-loads', + ajaxLoadMoreBtnClass: 'a2g-ajax-loadmore-btn', + ajaxLoadMoreBtnWrapClass: 'a2g-ajax-loadmore-btn-wrap', + ajaxSpinnerClass: 'a2g-ajax-spinner', + ajaxLoadingSpinner: '

', + checkIfFilterIsFilledOnInit: function () { + + }, + initFormSubmit: function (_this, ajaxForms, i) { + ajaxForms[i].querySelector('.' + _this.ajaxFormClass).addEventListener("submit", function (e) { + e.preventDefault(); + _this.formSubmitAction(_this, this); + return false; + }); + }, + formSubmitAction: function(_this, activeForm){ + var activeContent = activeForm.closest('.' + _this.wrapClass).querySelector('.' + _this.ajaxContentClass); + activeContent.innerHTML = _this.ajaxLoadingSpinner; + activeForm.querySelector('.' + _this.ajaxLoadMoreInputClass).value = 0; + jQuery.ajax({ + async: 'true', + url: $(activeForm).attr('action'), + type: 'POST', + data: $(activeForm).serializeArray(), + dataType: 'html', + success: function (result) { + activeForm.closest('.' + _this.wrapClass).querySelector('.' + _this.ajaxContentClass).innerHTML = result; + _this.initLoadMore(_this, activeContent.querySelector('.' + _this.ajaxLoadMoreBtnClass)); + if (typeof (a2gShop) === 'object') { + a2gShop.cart.setCartActions(a2gShop.cart, activeContent.getElementsByClassName(a2gShop.cart.productWrapClass)); + } + }, + error: function (error) { + // console.log(error); + }, + done: function () { + } + }); + }, + initLoadMore: function (_this, btn) { + if (btn !== null) { + + btn.addEventListener("click", function () { + var activeForm = this.closest('.' + _this.wrapClass).querySelector('.' + _this.ajaxFormClass), + activeContent = this.closest('.' + _this.wrapClass).querySelector('.' + _this.ajaxContentClass); + activeContent.innerHTML += _this.ajaxLoadingSpinner; + activeContent.removeChild(activeContent.querySelector('.' + _this.ajaxLoadMoreBtnWrapClass)); + activeForm.querySelector('.' + _this.ajaxLoadMoreInputClass).value = parseInt(activeForm.querySelector('.' + _this.ajaxLoadMoreInputClass).value) + 1; + jQuery.ajax({ + async: 'true', + url: $(activeForm).attr('action'), + type: 'POST', + data: $(activeForm).serializeArray(), + dataType: 'html', + success: function (result) { + activeContent.removeChild(activeContent.querySelector('.' + _this.ajaxSpinnerClass)); + activeContent.innerHTML += result; + _this.initLoadMore(_this, activeContent.querySelector('.' + _this.ajaxLoadMoreBtnClass)); + if (typeof (a2gShop) === 'object') { + a2gShop.cart.setCartActions(a2gShop.cart, activeContent.getElementsByClassName(a2gShop.cart.productWrapClass)); + } + }, + error: function (error) { + // console.log(error); + }, + done: function () { + } + }); + }); + } + }, + init: function () { + var _this = this, ajaxForms = document.getElementsByClassName(_this.wrapClass), inputs = []; + document.addEventListener('DOMContentLoaded', function () { + for (var i = 0; i < ajaxForms.length; i++) { + inputs[i] = ajaxForms[i].getElementsByClassName(_this.filterInputClass); + for (var j = 0; j < inputs[i]; j++){ + inputs[i].checked = false; + } + if (ajaxForms[i].querySelector('.' + _this.ajaxFormClass) !== null) { + _this.initFormSubmit(_this, ajaxForms, i); + _this.initLoadMore(_this, ajaxForms[i].querySelector('.' + _this.ajaxLoadMoreBtnClass)); + } + } + }); + } +}; +a2gProductsList.init(); + +var a2gUri = { + encode: function(uri){ + return encodeURIComponent(uri); + }, + mailto: function(mailto, subject, body){ + var _this = a2gUri; + if(typeof(mailto) === 'string' && typeof(subject) === 'string' && typeof(body) === 'string'){ + return 'mailto:'+mailto+'?subject='+_this.encode(subject)+'&body='+_this.encode(body); + } else if(typeof(mailto) === 'string' && typeof(subject) === 'string'){ + return 'mailto:'+_this.encode(mailto)+'?subject='+_this.encode(subject); + } else if(typeof(mailto) === 'string'){ + return 'mailto:'+mailto; + } + } +}; + +var a2gProductsDetail = { + class: { + wrap: 'a2g-product-detail', + variant: { + tab: 'a2g-product-variant-tab' + }, + request: { + mail: 'a2g-product-request-mail' + } + }, + setRequestBtnLink: function(subject, body) { + var _this = a2gProductsDetail; + var btns = document.getElementsByClassName(_this.class.request.mail); + for( var i = 0; i < btns.length; i++){ + btns[i].setAttribute('href', a2gUri.mailto(btns[i].dataset.mailto, subject, body)); + } + }, + getVariantTabTriggerElement: function() { + var _this = a2gProductsDetail, triggerEle = document.querySelector('.'+_this.class.variant.tab+'[data-href="' + window.location.href + '"]'); + if (triggerEle === null) { + triggerEle = document.querySelector('.'+_this.class.variant.tab+'[data-href="' + window.location.pathname + '"]'); + } + return triggerEle; + }, + fromHistoryBack: false, + init: function(){ + var _this = a2gProductsDetail; + if (document.getElementsByClassName(_this.class.wrap)[0] !== null) { + var tabEl = document.getElementsByClassName(_this.class.variant.tab); + for (var i = 0; i < tabEl.length; i++) { + tabEl[i].addEventListener('shown.bs.tab', function (event) { + if (!_this.fromHistoryBack) { + history.pushState({ + id: 'homepage-article' + }, 'altogether product detail', this.dataset.href); + } + _this.fromHistoryBack = false; + _this.setRequestBtnLink(this.dataset.subject, this.dataset.href); + }); + } + window.addEventListener('popstate', function (event) { + var triggerEle = a2gProductsDetail.getVariantTabTriggerElement(); + if (triggerEle !== null) { + _this.fromHistoryBack = true; + triggerEle.click(); + } + }); + var triggerEle = a2gProductsDetail.getVariantTabTriggerElement(); + if (triggerEle !== null) { + if (!triggerEle.classList.contains('active')) { + triggerEle.click(); + } + } + } + } + +} + +a2gProductsDetail.init(); \ No newline at end of file diff --git a/Resources/Public/JavaScript/a2gProductsSwiper.init.js b/Resources/Public/JavaScript/a2gProductsSwiper.init.js new file mode 100755 index 0000000..80c7bdf --- /dev/null +++ b/Resources/Public/JavaScript/a2gProductsSwiper.init.js @@ -0,0 +1,86 @@ +var a2gProductsSwiper = { + a2gCardSwiper: null, + initCardSwiper: function (_this) { + _this.a2gCardSwiper = new Swiper(".a2g-products-swiper-card", { + slidesPerView: 1, + spaceBetween: 10, + autoHeight: false, + loop: true, + init: true, + freeMode: false, + observer: true, + resizeObserver: true, + setWrapperSize: true, + preloadImages: true, + autoplay: { + delay: 7000, + disableOnInteraction: true + }, + pagination: { + el: ".swiper-pagination", + clickable: true + }, + breakpoints: { + 640: { + slidesPerView: 2, + spaceBetween: 15 + }, + 1024: { + slidesPerView: 3, + spaceBetween: 30 + } + } + }); + + }, + a2gImageSwiper: null, + a2gImageThumbSwiper: null, + initImageSwiper: function (_this) { + var sliders = document.getElementsByClassName("a2g-products-swiper-images-wrap"); + _this.a2gImageThumbSwiper = []; + _this.a2gImageSwiper = []; + for (var i = 0; i < sliders.length; i++) { + _this.a2gImageThumbSwiper[i] = new Swiper('#' + sliders[i].querySelector(".a2g-products-swiper-images-thumb").id, { + loop: true, + spaceBetween: 10, + slidesPerView: 4, + freeMode: false, + autoHeight: false, + watchSlidesProgress: true, + setWrapperSize: true, + preloadImages: true, + observer: true, + resizeObserver: true + }); + _this.a2gImageSwiper[i] = new Swiper('#' + sliders[i].querySelector(".a2g-products-swiper-images").id, { + loop: true, + spaceBetween: 10, + autoHeight: true, + freeMode: false, + observer: true, + resizeObserver: true, + setWrapperSize: true, + preloadImages: true, + effect: 'slide', + thumbs: { + swiper: _this.a2gImageThumbSwiper[i] + } + }); + } + }, + init: function () { + var _this = this; + _this.initCardSwiper(_this); + _this.initImageSwiper(_this); + document.addEventListener('DOMContentLoaded', function () { + _this.a2gCardSwiper.init(); + for (var i = 0; i < _this.a2gImageThumbSwiper.length; i++) { + _this.a2gImageSwiper[i].init(); + _this.a2gImageThumbSwiper[i].init(); + } + }); + + } +}; + +a2gProductsSwiper.init(); \ No newline at end of file diff --git a/Resources/Public/JavaScript/rSlider.min.js b/Resources/Public/JavaScript/rSlider.min.js new file mode 100755 index 0000000..c960803 --- /dev/null +++ b/Resources/Public/JavaScript/rSlider.min.js @@ -0,0 +1,11 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + * + * https://github.com/slawomir-zaziablo/range-slider + * + */ + + +!function(){"use strict";var t=function(t){this.input=null,this.inputDisplay=null,this.slider=null,this.sliderWidth=0,this.sliderLeft=0,this.pointerWidth=0,this.pointerR=null,this.pointerL=null,this.activePointer=null,this.selected=null,this.scale=null,this.step=0,this.tipL=null,this.tipR=null,this.timeout=null,this.valRange=!1,this.values={start:null,end:null},this.conf={target:null,values:null,set:null,range:!1,width:null,scale:!0,labels:!0,tooltip:!0,step:null,disabled:!1,onChange:null},this.cls={container:"rs-container",background:"rs-bg",selected:"rs-selected",pointer:"rs-pointer",scale:"rs-scale",noscale:"rs-noscale",tip:"rs-tooltip"};for(var i in this.conf)t.hasOwnProperty(i)&&(this.conf[i]=t[i]);this.init()};t.prototype.init=function(){return"object"==typeof this.conf.target?this.input=this.conf.target:this.input=document.getElementById(this.conf.target.replace("#","")),this.input?(this.inputDisplay=getComputedStyle(this.input,null).display,this.input.style.display="none",this.valRange=!(this.conf.values instanceof Array),!this.valRange||this.conf.values.hasOwnProperty("min")&&this.conf.values.hasOwnProperty("max")?this.createSlider():console.log("Missing min or max value...")):console.log("Cannot find target element...")},t.prototype.createSlider=function(){return this.slider=i("div",this.cls.container),this.slider.innerHTML='
',this.selected=i("div",this.cls.selected),this.pointerL=i("div",this.cls.pointer,["dir","left"]),this.scale=i("div",this.cls.scale),this.conf.tooltip&&(this.tipL=i("div",this.cls.tip),this.tipR=i("div",this.cls.tip),this.pointerL.appendChild(this.tipL)),this.slider.appendChild(this.selected),this.slider.appendChild(this.scale),this.slider.appendChild(this.pointerL),this.conf.range&&(this.pointerR=i("div",this.cls.pointer,["dir","right"]),this.conf.tooltip&&this.pointerR.appendChild(this.tipR),this.slider.appendChild(this.pointerR)),this.input.parentNode.insertBefore(this.slider,this.input.nextSibling),this.conf.width&&(this.slider.style.width=parseInt(this.conf.width)+"px"),this.sliderLeft=this.slider.getBoundingClientRect().left,this.sliderWidth=this.slider.clientWidth,this.pointerWidth=this.pointerL.clientWidth,this.conf.scale||this.slider.classList.add(this.cls.noscale),this.setInitialValues()},t.prototype.setInitialValues=function(){if(this.disabled(this.conf.disabled),this.valRange&&(this.conf.values=s(this.conf)),this.values.start=0,this.values.end=this.conf.range?this.conf.values.length-1:0,this.conf.set&&this.conf.set.length&&n(this.conf)){var t=this.conf.set;this.conf.range?(this.values.start=this.conf.values.indexOf(t[0]),this.values.end=this.conf.set[1]?this.conf.values.indexOf(t[1]):null):this.values.end=this.conf.values.indexOf(t[0])}return this.createScale()},t.prototype.createScale=function(t){this.step=this.sliderWidth/(this.conf.values.length-1);for(var e=0,s=this.conf.values.length;ethis.conf.values.length-1&&(i=this.conf.values.length-1),this.conf.range?(this.activePointer===this.pointerL&&(this.values.start=i),this.activePointer===this.pointerR&&(this.values.end=i)):this.values.end=i,this.setValues()}},t.prototype.drop=function(){this.activePointer=null},t.prototype.setValues=function(t,i){var e=this.conf.range?"start":"end";return t&&this.conf.values.indexOf(t)>-1&&(this.values[e]=this.conf.values.indexOf(t)),i&&this.conf.values.indexOf(i)>-1&&(this.values.end=this.conf.values.indexOf(i)),this.conf.range&&this.values.start>this.values.end&&(this.values.start=this.values.end),this.pointerL.style.left=this.values[e]*this.step-this.pointerWidth/2+"px",this.conf.range?(this.conf.tooltip&&(this.tipL.innerHTML=this.conf.values[this.values.start],this.tipR.innerHTML=this.conf.values[this.values.end]),this.input.value=this.conf.values[this.values.start]+","+this.conf.values[this.values.end],this.pointerR.style.left=this.values.end*this.step-this.pointerWidth/2+"px"):(this.conf.tooltip&&(this.tipL.innerHTML=this.conf.values[this.values.end]),this.input.value=this.conf.values[this.values.end]),this.values.end>this.conf.values.length-1&&(this.values.end=this.conf.values.length-1),this.values.start<0&&(this.values.start=0),this.selected.style.width=(this.values.end-this.values.start)*this.step+"px",this.selected.style.left=this.values.start*this.step+"px",this.onChange()},t.prototype.onClickPiece=function(t){if(!this.conf.disabled){var i=Math.round((t.clientX-this.sliderLeft)/this.step);return i>this.conf.values.length-1&&(i=this.conf.values.length-1),i<0&&(i=0),this.conf.range&&i-this.values.start<=this.values.end-i?this.values.start=i:this.values.end=i,this.slider.classList.remove("sliding"),this.setValues()}},t.prototype.onChange=function(){var t=this;this.timeout&&clearTimeout(this.timeout),this.timeout=setTimeout(function(){if(t.conf.onChange&&"function"==typeof t.conf.onChange)return t.conf.onChange(t.input.value)},500)},t.prototype.onResize=function(){return this.sliderLeft=this.slider.getBoundingClientRect().left,this.sliderWidth=this.slider.clientWidth,this.updateScale()},t.prototype.disabled=function(t){this.conf.disabled=t,this.slider.classList[t?"add":"remove"]("disabled")},t.prototype.getValue=function(){return this.input.value},t.prototype.destroy=function(){this.input.style.display=this.inputDisplay,this.slider.remove()};var i=function(t,i,e){var s=document.createElement(t);return i&&(s.className=i),e&&2===e.length&&s.setAttribute("data-"+e[0],e[1]),s},e=function(t,i,e){for(var s=i.split(" "),n=0,l=s.length;n' +/usr/share/koala/bin/sass:22:in `load' +/usr/share/koala/bin/sass:22:in `
' +*/ +body:before { + white-space: pre; + font-family: monospace; + content: "Error: $color: \"var(--bs-primary-rgb)\" is not a color for `rgba'\A on line 41 of /home/raphy/NetBeansProjects/altogether_DEV/public/typo3conf/ext/bootstrap_package/Resources/Public/Contrib/bootstrap5/scss/_functions.scss\A from line 11 of /home/raphy/NetBeansProjects/altogether_DEV/public/typo3conf/ext/a2g_products/Resources/Public/Scss/a2gProductsList.scss"; } diff --git a/Resources/Public/Scss/a2gProductsList.scss b/Resources/Public/Scss/a2gProductsList.scss new file mode 100755 index 0000000..aa4f7b5 --- /dev/null +++ b/Resources/Public/Scss/a2gProductsList.scss @@ -0,0 +1,51 @@ +/* +To change this license header, choose License Headers in Project Properties. +To change this template file, choose Tools | Templates +and open the template in the editor. +*/ +/* + Created on : Aug 11, 2021, 11:24:31 AM + Author : Raphael Martin +*/ +@import "../../../../bootstrap_package/Resources/Public/Contrib/bootstrap5/scss/_functions.scss"; +@import "../../../../bootstrap_package/Resources/Public/Contrib/bootstrap5/scss/_variables.scss"; +@import "../../../../bootstrap_package/Resources/Public/Contrib/bootstrap5/scss/mixins"; + +.frame-background-secondary{ + .altogether-products{ + .btn-secondary{ + @include button-variant($primary, $primary); + color: $dark; + } + } +} + +.frame-background-primary{ + .altogether-products{ + .btn-primary{ + @include button-variant($secondary, $secondary); + color: $light; + } + } +} +.a2g-product-card-group-element-columns-2 { + @include media-breakpoint-up('md') { + --cardgroup-columns: 2; + } +} +.a2g-product-card-group-element-columns-3 { + @include media-breakpoint-up('md') { + --cardgroup-columns: 2; + } + @include media-breakpoint-up('lg') { + --cardgroup-columns: 3; + } +} +.a2g-product-card-group-element-columns-3-sm { + @include media-breakpoint-up('sm') { + --cardgroup-columns: 2; + } + @include media-breakpoint-up('lg') { + --cardgroup-columns: 3; + } +} \ No newline at end of file diff --git a/Resources/Public/Scss/rSlider.min.scss b/Resources/Public/Scss/rSlider.min.scss new file mode 100755 index 0000000..c5618bc --- /dev/null +++ b/Resources/Public/Scss/rSlider.min.scss @@ -0,0 +1 @@ +.rs-container *{box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.rs-container{font-family:Arial,Helvetica,sans-serif;height:45px;position:relative}.rs-container .rs-bg,.rs-container .rs-selected{background-color:#eee;border:1px solid #ededed;height:10px;left:0;position:absolute;top:5px;width:100%;border-radius:3px}.rs-container .rs-selected{background-color:#00b3bc;border:1px solid #00969b;transition:all .2s linear;width:0}.rs-container.disabled .rs-selected{background-color:#ccc;border-color:#bbb}.rs-container .rs-pointer{background-color:#fff;border:1px solid #bbb;border-radius:4px;cursor:pointer;height:20px;left:-10px;position:absolute;top:0;transition:all .2s linear;width:30px;box-shadow:inset 0 0 1px #FFF,inset 0 1px 6px #ebebeb,1px 1px 4px rgba(0,0,0,.1)}.rs-container.disabled .rs-pointer{border-color:#ccc;cursor:default}.rs-container .rs-pointer::after,.rs-container .rs-pointer::before{content:'';position:absolute;width:1px;height:9px;background-color:#ddd;left:12px;top:5px}.rs-container .rs-pointer::after{left:auto;right:12px}.rs-container.sliding .rs-pointer,.rs-container.sliding .rs-selected{transition:none}.rs-container .rs-scale{left:0;position:absolute;top:5px;white-space:nowrap}.rs-container .rs-scale span{float:left;position:relative}.rs-container .rs-scale span::before{background-color:#ededed;content:"";height:8px;left:0;position:absolute;top:10px;width:1px}.rs-container.rs-noscale span::before{display:none}.rs-container.rs-noscale span:first-child::before,.rs-container.rs-noscale span:last-child::before{display:block}.rs-container .rs-scale span:last-child{margin-left:-1px;width:0}.rs-container .rs-scale span ins{color:#333;display:inline-block;font-size:12px;margin-top:20px;text-decoration:none}.rs-container.disabled .rs-scale span ins{color:#999}.rs-tooltip{color:#333;width:auto;min-width:60px;height:30px;background:#fff;border:1px solid #00969b;border-radius:3px;position:absolute;transform:translate(-50%,-35px);left:13px;text-align:center;font-size:13px;padding:6px 10px 0}.rs-container.disabled .rs-tooltip{border-color:#ccc;color:#999} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..3e18786 --- /dev/null +++ b/composer.json @@ -0,0 +1,47 @@ +{ + "name": "altogether/a2g-products", + "type": "typo3-cms-extension", + "description": "", + "authors": [ + { + "name": "Raphael Martin", + "role": "Developer" + } + ], + "license": "GPL-2.0-or-later", + "require": { + "typo3/cms-core": "^10.4" + }, + "require-dev": { + "typo3/testing-framework": "^6.8" + }, + "autoload": { + "psr-4": { + "A2G\\A2gProducts\\": "Classes" + } + }, + "autoload-dev": { + "psr-4": { + "A2G\\A2gProducts\\Tests\\": "Tests" + } + }, + "replace": { + "typo3-ter/a2g-products": "self.version" + }, + "config": { + "vendor-dir": ".Build/vendor", + "bin-dir": ".Build/bin" + }, + "scripts": { + "post-autoload-dump": [ + "TYPO3\\TestingFramework\\Composer\\ExtensionTestEnvironment::prepare" + ] + }, + "extra": { + "typo3/cms": { + "cms-package-dir": "{$vendor-dir}/typo3/cms", + "web-dir": ".Build/public", + "extension-key": "a2g_products" + } + } +} \ No newline at end of file diff --git a/ext_emconf.php b/ext_emconf.php new file mode 100755 index 0000000..d36ef52 --- /dev/null +++ b/ext_emconf.php @@ -0,0 +1,30 @@ + 'altogether Products', + 'description' => '', + 'category' => 'plugin', + 'author' => 'Raphael Martin', + 'author_email' => 'raphy.martin@gmail.com', + 'state' => 'alpha', + 'clearCacheOnLoad' => 0, + 'version' => '1.0.0', + 'constraints' => [ + 'depends' => [ + 'typo3' => '10.4.0-12.1.99', + 'a2g_toolkit' => '1.0.1-1.5.99' + ], + 'conflicts' => [], + 'suggests' => [], + ], +]; diff --git a/ext_localconf.php b/ext_localconf.php new file mode 100755 index 0000000..dd25457 --- /dev/null +++ b/ext_localconf.php @@ -0,0 +1,131 @@ +'); + +call_user_func(static function() { + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'A2gProducts', + 'A2gproductslist', + [ + \A2G\A2gProducts\Controller\ProductsController::class => 'list, ajaxList, show' + ], + // non-cacheable actions + [ + \A2G\A2gProducts\Controller\ProductsController::class => '' + ] + ); + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'A2gProducts', + 'A2gproductsdetail', + [ + \A2G\A2gProducts\Controller\ProductsController::class => 'show' + ], + // non-cacheable actions + [ + \A2G\A2gProducts\Controller\ProductsController::class => '' + ] + ); + + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'A2gProducts', + 'Ingredientslist', + [ + \A2G\A2gProducts\Controller\IngredientsController::class => 'list, show' + ], + // non-cacheable actions + [ + \A2G\A2gProducts\Controller\IngredientsController::class => '' + ] + ); + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'A2gProducts', + 'Ingredientsdetail', + [ + \A2G\A2gProducts\Controller\IngredientsController::class => 'show' + ], + // non-cacheable actions + [ + \A2G\A2gProducts\Controller\IngredientsController::class => '' + ] + ); + + + // wizards + /* + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig( + 'mod { + wizards.newContentElement.wizardItems.plugins { + elements { + a2gproductslist { + iconIdentifier = a2g_products-plugin-a2gproductslist + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductslist.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductslist.description + tt_content_defValues { + CType = list + list_type = a2gproducts_a2gproductslist + } + } + a2gproductsdetail { + iconIdentifier = a2g_products-plugin-a2gproductsdetail + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductsdetail.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_a2gproductsdetail.description + tt_content_defValues { + CType = list + list_type = a2gproducts_a2gproductsdetail + } + } + ingredientslist { + iconIdentifier = a2g_products-plugin-ingredientslist + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientslist.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientslist.description + tt_content_defValues { + CType = list + list_type = a2gproducts_ingredientslist + } + } + ingredientsdetail { + iconIdentifier = a2g_products-plugin-ingredientsdetail + title = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientsdetail.name + description = LLL:EXT:a2g_products/Resources/Private/Language/locallang_db.xlf:tx_a2g_products_ingredientsdetail.description + tt_content_defValues { + CType = list + list_type = a2gproducts_ingredientsdetail + } + } + } + show = * + } + }' + ); + */ + + $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class); + $iconRegistry->registerIcon( + 'a2g_products-plugin-a2gproductslist', + \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, + ['source' => 'EXT:a2g_products/Resources/Public/Icons/online-shopping.png'] + ); + $iconRegistry->registerIcon( + 'a2g_products-plugin-a2gproductsdetail', + \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, + ['source' => 'EXT:a2g_products/Resources/Public/Icons/online-shopping.png'] + ); + $iconRegistry->registerIcon( + 'a2g_products-plugin-ingredientslist', + \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, + ['source' => 'EXT:a2g_products/Resources/Public/Icons/natural-ingredients.png'] + ); + $iconRegistry->registerIcon( + 'a2g_products-plugin-ingredientsdetail', + \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, + ['source' => 'EXT:a2g_products/Resources/Public/Icons/natural-ingredients.png'] + ); +}); + +/*************** + * Register "a2g" as global fluid namespace + */ +$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['a2gprod'][] = 'A2G\\A2gProducts\\ViewHelpers'; diff --git a/ext_tables.php b/ext_tables.php new file mode 100755 index 0000000..63890e1 --- /dev/null +++ b/ext_tables.php @@ -0,0 +1,52 @@ + 'flexform_list', + 'a2gproducts_a2gproductsdetail' => 'flexform_detail', + 'a2gproducts_ingredientslist' => 'flexform_ingredients_list', + 'a2gproducts_ingredientsdetail' => 'flexform_ingredients_detail' +]; + +foreach ($pluginSignatures as $pluginSignature => $flexform) { + $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginSignature] = 'pi_flexform'; + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue($pluginSignature, 'FILE:EXT:a2g_products/Configuration/FlexForms/' . $flexform . '.xml'); +} +/** + * COMPOSER - load in ext used composer stuff + */ +//$composerAutoloadFile = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('webx_gs_map') . 'Resources/Private/PHP/autoload.php'; +//require_once($composerAutoloadFile); + +/** + * SIGNAL SLOT - Canonical + */ +//$signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class); +//$signalSlotDispatcher->connect( +// \TYPO3\CMS\Seo\Canonical\CanonicalGenerator::class, +// 'beforeGeneratingCanonical', +// \A2G\A2gProducts\Utility\CanonicalUtility::class, +// 'setCanonical' +//); diff --git a/ext_tables.sql b/ext_tables.sql new file mode 100755 index 0000000..255e41a --- /dev/null +++ b/ext_tables.sql @@ -0,0 +1,170 @@ +CREATE TABLE tx_a2gproducts_domain_model_brands ( + title varchar(120) NOT NULL DEFAULT '', + image int(11) unsigned NOT NULL DEFAULT '0', + page_uid int(11) unsigned NOT NULL DEFAULT '0' +); + +CREATE TABLE tx_a2gproducts_domain_model_products ( + nr varchar(80) NOT NULL DEFAULT '', + title varchar(120) NOT NULL DEFAULT '', + path_segment varchar(80) DEFAULT '' NOT NULL, + description text NOT NULL DEFAULT '', + description_html text NOT NULL DEFAULT '', + image int(11) unsigned NOT NULL DEFAULT '0', + images int(11) unsigned NOT NULL DEFAULT '0', + gallery int(11) unsigned NOT NULL DEFAULT '0', + seo_image1x1 int(11) unsigned NOT NULL DEFAULT '0', + seo_image4x3 int(11) unsigned NOT NULL DEFAULT '0', + seo_image16x9 int(11) unsigned NOT NULL DEFAULT '0', + rel_category int(11) unsigned NOT NULL DEFAULT '0', + rel_filter_values int(11) unsigned NOT NULL DEFAULT '0', + rel_selectableattribute int(11) unsigned NOT NULL DEFAULT '0', + rel_ingredients int(11) unsigned NOT NULL DEFAULT '0', + rel_productvariants int(11) unsigned NOT NULL DEFAULT '0', + rel_brand int(11) unsigned NOT NULL DEFAULT '0' +); + +CREATE TABLE tx_a2gproducts_domain_model_productvariants ( + nr varchar(80) NOT NULL DEFAULT '', + title varchar(120) NOT NULL DEFAULT '', + path_segment varchar(80) DEFAULT '' NOT NULL, + description text NOT NULL DEFAULT '', + description_html text NOT NULL DEFAULT '', + image int(11) unsigned NOT NULL DEFAULT '0', + images int(11) unsigned NOT NULL DEFAULT '0', + gallery int(11) unsigned NOT NULL DEFAULT '0', + seo_image1x1 int(11) unsigned NOT NULL DEFAULT '0', + seo_image4x3 int(11) unsigned NOT NULL DEFAULT '0', + seo_image16x9 int(11) unsigned NOT NULL DEFAULT '0', + rel_category int(11) unsigned NOT NULL DEFAULT '0', + rel_filter_values int(11) unsigned NOT NULL DEFAULT '0', + rel_selectableattribute int(11) unsigned NOT NULL DEFAULT '0', + rel_ingredients int(11) unsigned NOT NULL DEFAULT '0', + product int(11) unsigned NOT NULL DEFAULT '0', + rel_brand int(11) NOT NULL DEFAULT '0', + rel_sizes int(11) NOT NULL DEFAULT '0', + tab_icon int(11) unsigned NOT NULL DEFAULT '0' +); +CREATE TABLE tx_a2gproducts_domain_model_productvariantsizes ( + nr varchar(80) NOT NULL DEFAULT '', + title varchar(120) NOT NULL DEFAULT '', + path_segment varchar(80) DEFAULT '' NOT NULL, + description text NOT NULL DEFAULT '', + productvariant int(11) unsigned NOT NULL DEFAULT '0' +); + + +CREATE TABLE tx_a2gproducts_domain_model_categories ( + title varchar(80) NOT NULL DEFAULT '', + description varchar(255) NOT NULL DEFAULT '', + image int(11) unsigned NOT NULL DEFAULT '0', + rel_filters int(11) unsigned NOT NULL DEFAULT '0' +); + +CREATE TABLE tx_a2gproducts_domain_model_filters ( + title varchar(80) NOT NULL DEFAULT '', + filter_type int(11) NOT NULL DEFAULT '0', + filter_output_type int(11) NOT NULL DEFAULT '0', + db_operation_max int(11) NOT NULL DEFAULT '0', + db_operation_min int(11) NOT NULL DEFAULT '0', + rel_filter_option int(11) unsigned NOT NULL DEFAULT '0' +); + +CREATE TABLE tx_a2gproducts_domain_model_filteroptions ( + filters int(11) unsigned DEFAULT '0' NOT NULL, + title varchar(255) NOT NULL DEFAULT '', + value_min double(11,2) NOT NULL DEFAULT '0.00', + value_max double(11,2) NOT NULL DEFAULT '0.00' +); + +CREATE TABLE tx_a2gproducts_domain_model_filtervalues ( + products int(11) unsigned DEFAULT '0' NOT NULL, + productvariants int(11) unsigned DEFAULT '0' NOT NULL, + value double(11,2) NOT NULL DEFAULT '0.00', + rel_filters int(11) unsigned DEFAULT '0', + rel_filter_option int(11) unsigned DEFAULT '0' +); + +CREATE TABLE tx_a2gproducts_products_categories_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid_local,uid_foreign), + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); + +CREATE TABLE tx_a2gproducts_productvariants_categories_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid_local,uid_foreign), + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); + +CREATE TABLE tx_a2gproducts_categories_filters_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid_local,uid_foreign), + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); + +CREATE TABLE tx_a2gproducts_domain_model_ingredients( + title varchar(80) NOT NULL DEFAULT '', + path_segment varchar(80) DEFAULT '' NOT NULL, + description text NOT NULL DEFAULT '', + image int(11) unsigned NOT NULL DEFAULT '0', + images int(11) unsigned NOT NULL DEFAULT '0', + gallery int(11) unsigned NOT NULL DEFAULT '0', + rel_products int(11) unsigned NOT NULL DEFAULT '0', + rel_productvariants int(11) unsigned NOT NULL DEFAULT '0' +); + +CREATE TABLE tx_a2gproducts_products_ingredients_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid_local,uid_foreign), + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); + +CREATE TABLE tx_a2gproducts_productvarinats_ingredients_mm ( + uid_local int(11) unsigned DEFAULT '0' NOT NULL, + uid_foreign int(11) unsigned DEFAULT '0' NOT NULL, + sorting int(11) unsigned DEFAULT '0' NOT NULL, + sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL, + + PRIMARY KEY (uid_local,uid_foreign), + KEY uid_local (uid_local), + KEY uid_foreign (uid_foreign) +); + +CREATE TABLE sys_file ( + images int(11) unsigned DEFAULT '0' NOT NULL +); + +CREATE TABLE tx_a2gtoolkit_masonry_item ( + a2g_ingredients int(11) unsigned DEFAULT '0' NOT NULL, + a2g_products int(11) unsigned DEFAULT '0' NOT NULL, + a2g_productvariants int(11) unsigned DEFAULT '0' NOT NULL, +); + +CREATE TABLE tx_a2gproducts_domain_model_selectableattribute ( + products int(11) unsigned DEFAULT '0' NOT NULL, + productvariants int(11) unsigned DEFAULT '0' NOT NULL, + rel_filters int(11) unsigned DEFAULT '0', + rel_filter_option int(11) unsigned DEFAULT '0', + title varchar(80) DEFAULT '' NOT NULL, +); \ No newline at end of file