| ... | ... |
@@ -8,6 +8,7 @@ |
| 8 | 8 |
* @license commercial |
| 9 | 9 |
*/ |
| 10 | 10 |
|
| 11 |
+use vonRotenberg\RealEstateListingBundle\Model\ManagedPropertyModel; |
|
| 11 | 12 |
use vonRotenberg\RealEstateListingBundle\Model\RealEstateAssetsModel; |
| 12 | 13 |
use Contao\System; |
| 13 | 14 |
use Contao\ArrayUtil; |
| ... | ... |
@@ -17,6 +18,9 @@ ArrayUtil::arrayInsert($GLOBALS['BE_MOD'], 1, [ |
| 17 | 18 |
'vr_real_estate' => [ |
| 18 | 19 |
'vr_re_categories' => [ |
| 19 | 20 |
'tables' => array('tl_vr_real_estate_categories','tl_vr_real_estate_assets')
|
| 21 |
+ ], |
|
| 22 |
+ 'managed_properties' => [ |
|
| 23 |
+ 'tables' => ['tl_vr_re_managedProperties'], |
|
| 20 | 24 |
] |
| 21 | 25 |
] |
| 22 | 26 |
]); |
| ... | ... |
@@ -31,5 +35,6 @@ if ($requestStack->getCurrentRequest() !== null && $scopeMatcher->isBackendReque |
| 31 | 35 |
|
| 32 | 36 |
$GLOBALS['TL_MODELS']['tl_vr_real_estate_assets'] = RealEstateAssetsModel::class; |
| 33 | 37 |
$GLOBALS['TL_MODELS']['tl_vr_real_estate_categories'] = RealEstateCategoriesModel::class; |
| 38 |
+$GLOBALS['TL_MODELS']['tl_vr_re_managedProperties'] = ManagedPropertyModel::class; |
|
| 34 | 39 |
|
| 35 | 40 |
|
| ... | ... |
@@ -8,6 +8,8 @@ |
| 8 | 8 |
* @license commercial |
| 9 | 9 |
*/ |
| 10 | 10 |
|
| 11 |
+use vonRotenberg\RealEstateListingBundle\Controller\FrontendModule\ManagedPropertyController; |
|
| 12 |
+use vonRotenberg\RealEstateListingBundle\Controller\FrontendModule\ManagedPropertyReaderController; |
|
| 11 | 13 |
use vonRotenberg\RealEstateListingBundle\Controller\FrontendModule\RealEstateAssetsAdController; |
| 12 | 14 |
use vonRotenberg\RealEstateListingBundle\Controller\FrontendModule\RealEstateAssetsListController; |
| 13 | 15 |
use vonRotenberg\RealEstateListingBundle\Controller\FrontendModule\RealEstateAssetsReaderController; |
| ... | ... |
@@ -15,6 +17,23 @@ use vonRotenberg\RealEstateListingBundle\Controller\FrontendModule\RealEstateAss |
| 15 | 17 |
$GLOBALS['TL_DCA']['tl_module']['palettes'][RealEstateAssetsListController::TYPE] = '{title_legend},name,headline,type;{real_estate_legend},vr_re_categories,imgSize,vr_re_grouped;{re_reader_legend},jumpTo;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
| 16 | 18 |
$GLOBALS['TL_DCA']['tl_module']['palettes'][RealEstateAssetsAdController::TYPE] = '{title_legend},name,headline,type;{real_estate_legend},vr_re_categories;{re_reader_legend},jumpTo;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
| 17 | 19 |
$GLOBALS['TL_DCA']['tl_module']['palettes'][RealEstateAssetsReaderController::TYPE] = '{title_legend},name,headline,type;{real_estate_legend},imgSize;{re_form_legend},vr_re_formUrl;{re_overview_legend},jumpTo;{template_legend:hide},customTpl;{protected_legend:hide},protected;{expert_legend:hide},guests,cssID';
|
| 20 |
+$GLOBALS['TL_DCA']['tl_module']['palettes'][ManagedPropertyController::TYPE] = ' |
|
| 21 |
+ {title_legend},name,headline,type;
|
|
| 22 |
+ {image_legend},imgSize;
|
|
| 23 |
+ {re_reader_legend},jumpTo;
|
|
| 24 |
+ {template_legend:hide},customTpl;
|
|
| 25 |
+ {protected_legend:hide},protected;
|
|
| 26 |
+ {expert_legend:hide},cssID
|
|
| 27 |
+'; |
|
| 28 |
+ |
|
| 29 |
+$GLOBALS['TL_DCA']['tl_module']['palettes'][ManagedPropertyReaderController::TYPE] = ' |
|
| 30 |
+ {title_legend},name,headline,type;
|
|
| 31 |
+ {image_legend},imgSize;
|
|
| 32 |
+ {re_overview_legend},jumpTo;
|
|
| 33 |
+ {template_legend:hide},customTpl;
|
|
| 34 |
+ {protected_legend:hide},protected;
|
|
| 35 |
+ {expert_legend:hide},cssID
|
|
| 36 |
+'; |
|
| 18 | 37 |
|
| 19 | 38 |
$GLOBALS['TL_DCA']['tl_module']['fields']['vr_re_categories'] = [ |
| 20 | 39 |
'exclude' => true, |
| 21 | 40 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,184 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+declare(strict_types=1); |
|
| 4 |
+ |
|
| 5 |
+/** |
|
| 6 |
+ * OBG Customizations |
|
| 7 |
+ * |
|
| 8 |
+ * Copyright (c) 2021 vonRotenberg |
|
| 9 |
+ * |
|
| 10 |
+ * @license commercial |
|
| 11 |
+ */ |
|
| 12 |
+ |
|
| 13 |
+use Contao\DC_Table; |
|
| 14 |
+use Contao\DataContainer; |
|
| 15 |
+ |
|
| 16 |
+$GLOBALS['TL_DCA']['tl_vr_re_managedProperties'] = array |
|
| 17 |
+( |
|
| 18 |
+ // Config |
|
| 19 |
+ 'config' => array |
|
| 20 |
+ ( |
|
| 21 |
+ 'dataContainer' => DC_Table::class, |
|
| 22 |
+ 'enableVersioning' => true, |
|
| 23 |
+ 'markAsCopy' => 'address', |
|
| 24 |
+ 'sql' => array |
|
| 25 |
+ ( |
|
| 26 |
+ 'keys' => array |
|
| 27 |
+ ( |
|
| 28 |
+ 'id' => 'primary', |
|
| 29 |
+ ) |
|
| 30 |
+ ) |
|
| 31 |
+ ), |
|
| 32 |
+ |
|
| 33 |
+ // List |
|
| 34 |
+ 'list' => array |
|
| 35 |
+ ( |
|
| 36 |
+ 'sorting' => array |
|
| 37 |
+ ( |
|
| 38 |
+ 'mode' => DataContainer::MODE_SORTABLE, |
|
| 39 |
+ 'fields' => array('address'),
|
|
| 40 |
+ 'flag' => DataContainer::SORT_INITIAL_LETTER_ASC, |
|
| 41 |
+ 'panelLayout' => 'filter;sort,search,limit' |
|
| 42 |
+ ), |
|
| 43 |
+ 'label' => array |
|
| 44 |
+ ( |
|
| 45 |
+ 'fields' => array('address'),
|
|
| 46 |
+ ), |
|
| 47 |
+ 'global_operations' => array |
|
| 48 |
+ ( |
|
| 49 |
+ 'all' => array |
|
| 50 |
+ ( |
|
| 51 |
+ 'href' => 'act=select', |
|
| 52 |
+ 'class' => 'header_edit_all', |
|
| 53 |
+ 'attributes' => 'onclick="Backend.getScrollOffset()" accesskey="e"' |
|
| 54 |
+ ) |
|
| 55 |
+ ), |
|
| 56 |
+ 'operations' => array |
|
| 57 |
+ ( |
|
| 58 |
+ 'edit' => array |
|
| 59 |
+ ( |
|
| 60 |
+ 'href' => 'act=edit', |
|
| 61 |
+ 'icon' => 'edit.svg', |
|
| 62 |
+ ), |
|
| 63 |
+ 'copy' => array |
|
| 64 |
+ ( |
|
| 65 |
+ 'href' => 'act=copy', |
|
| 66 |
+ 'icon' => 'copy.svg' |
|
| 67 |
+ ), |
|
| 68 |
+ 'delete' => array |
|
| 69 |
+ ( |
|
| 70 |
+ 'href' => 'act=delete', |
|
| 71 |
+ 'icon' => 'delete.svg', |
|
| 72 |
+ 'attributes' => 'onclick="if(!confirm(\'' . ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? null) . '\'))return false;Backend.getScrollOffset()"' |
|
| 73 |
+ ), |
|
| 74 |
+ 'toggle' => array( |
|
| 75 |
+ 'href' => 'act=toggle&field=published', |
|
| 76 |
+ 'icon' => 'visible.svg', |
|
| 77 |
+ ), |
|
| 78 |
+ 'show' => array |
|
| 79 |
+ ( |
|
| 80 |
+ 'href' => 'act=show', |
|
| 81 |
+ 'icon' => 'show.svg' |
|
| 82 |
+ ) |
|
| 83 |
+ ) |
|
| 84 |
+ ), |
|
| 85 |
+ |
|
| 86 |
+ // Palettes |
|
| 87 |
+ 'palettes' => array |
|
| 88 |
+ ( |
|
| 89 |
+ '__selector__' => array(), |
|
| 90 |
+ 'default' => '{data_legend},address,postal,city,gallerySRC;{description_legend},description;{map_legend},mapIframe;{publish_legend},published,start,stop',
|
|
| 91 |
+ ), |
|
| 92 |
+ |
|
| 93 |
+ // Subpalettes |
|
| 94 |
+ 'subpalettes' => array |
|
| 95 |
+ ( |
|
| 96 |
+ ), |
|
| 97 |
+ |
|
| 98 |
+ // Fields |
|
| 99 |
+ 'fields' => array |
|
| 100 |
+ ( |
|
| 101 |
+ 'id' => array |
|
| 102 |
+ ( |
|
| 103 |
+ 'sql' => "int(10) unsigned NOT NULL auto_increment" |
|
| 104 |
+ ), |
|
| 105 |
+ 'tstamp' => array |
|
| 106 |
+ ( |
|
| 107 |
+ 'sql' => "int(10) unsigned NOT NULL default 0" |
|
| 108 |
+ ), |
|
| 109 |
+ 'description' => array |
|
| 110 |
+ ( |
|
| 111 |
+ 'exclude' => true, |
|
| 112 |
+ 'inputType' => 'textarea', |
|
| 113 |
+ 'eval' => array('mandatory'=>false, 'rte'=>'tinyMCE', 'helpwizard'=>true, 'tl_class'=>'clr'),
|
|
| 114 |
+ 'explanation' => 'insertTags', |
|
| 115 |
+ 'sql' => "mediumtext NULL" |
|
| 116 |
+ ), |
|
| 117 |
+ 'postal' => array |
|
| 118 |
+ ( |
|
| 119 |
+ 'exclude' => true, |
|
| 120 |
+ 'inputType' => 'text', |
|
| 121 |
+ 'eval' => array('mandatory' => true, 'rgxp' => 'natural', 'maxlength' => 5, 'tl_class' => 'w50'),
|
|
| 122 |
+ 'sql' => "varchar(5) NOT NULL default ''" |
|
| 123 |
+ ), |
|
| 124 |
+ 'city' => array |
|
| 125 |
+ ( |
|
| 126 |
+ 'exclude' => true, |
|
| 127 |
+ 'inputType' => 'text', |
|
| 128 |
+ 'default' => 'Kehl', |
|
| 129 |
+ 'eval' => array('mandatory' => true, 'maxlength' => 255, 'tl_class' => 'w50'),
|
|
| 130 |
+ 'sql' => "varchar(255) NOT NULL default ''" |
|
| 131 |
+ ), |
|
| 132 |
+ 'address' => array |
|
| 133 |
+ ( |
|
| 134 |
+ 'exclude' => true, |
|
| 135 |
+ 'filter' => true, |
|
| 136 |
+ 'inputType' => 'text', |
|
| 137 |
+ 'eval' => array('mandatory' => false, 'maxlength' => 255, 'tl_class' => 'w50'),
|
|
| 138 |
+ 'sql' => "varchar(255) NOT NULL default ''" |
|
| 139 |
+ ), |
|
| 140 |
+ 'gallerySRC' => array |
|
| 141 |
+ ( |
|
| 142 |
+ 'exclude' => true, |
|
| 143 |
+ 'inputType' => 'fileTree', |
|
| 144 |
+ 'eval' => array('mandatory' => true, 'filesOnly' => true, 'fieldType' => 'checkbox', 'multiple' => true, 'tl_class' => 'clr', 'orderField' => 'orderSRC', 'files' => true, 'extensions' => \Contao\Config::get('validImageTypes'), 'isGallery' => true),
|
|
| 145 |
+ 'sql' => "blob NULL" |
|
| 146 |
+ ), |
|
| 147 |
+ 'orderSRC' => array |
|
| 148 |
+ ( |
|
| 149 |
+ 'label' => &$GLOBALS['TL_LANG']['MSC']['sortOrder'], |
|
| 150 |
+ 'sql' => "blob NULL" |
|
| 151 |
+ ), |
|
| 152 |
+ 'mapIframe' => array |
|
| 153 |
+ ( |
|
| 154 |
+ 'search' => true, |
|
| 155 |
+ 'inputType' => 'textarea', |
|
| 156 |
+ 'eval' => array('useRawRequestData'=>true, 'class'=>'monospace', 'rte'=>'ace|html', 'helpwizard'=>true),
|
|
| 157 |
+ 'explanation' => 'insertTags', |
|
| 158 |
+ 'sql' => "mediumtext NULL" |
|
| 159 |
+ ), |
|
| 160 |
+ 'published' => array |
|
| 161 |
+ ( |
|
| 162 |
+ 'exclude' => true, |
|
| 163 |
+ 'filter' => true, |
|
| 164 |
+ 'toggle' => true, |
|
| 165 |
+ 'inputType' => 'checkbox', |
|
| 166 |
+ 'eval' => array('doNotCopy' => true),
|
|
| 167 |
+ 'sql' => "char(1) NOT NULL default ''" |
|
| 168 |
+ ), |
|
| 169 |
+ 'start' => array |
|
| 170 |
+ ( |
|
| 171 |
+ 'exclude' => true, |
|
| 172 |
+ 'inputType' => 'text', |
|
| 173 |
+ 'eval' => array('rgxp' => 'datim', 'datepicker' => true, 'tl_class' => 'w50 wizard'),
|
|
| 174 |
+ 'sql' => "varchar(10) NOT NULL default ''" |
|
| 175 |
+ ), |
|
| 176 |
+ 'stop' => array |
|
| 177 |
+ ( |
|
| 178 |
+ 'exclude' => true, |
|
| 179 |
+ 'inputType' => 'text', |
|
| 180 |
+ 'eval' => array('rgxp' => 'datim', 'datepicker' => true, 'tl_class' => 'w50 wizard'),
|
|
| 181 |
+ 'sql' => "varchar(10) NOT NULL default ''" |
|
| 182 |
+ ) |
|
| 183 |
+ ) |
|
| 184 |
+); |
| ... | ... |
@@ -10,6 +10,12 @@ |
| 10 | 10 |
<trans-unit id="MOD.vr_re_categories.1"> |
| 11 | 11 |
<source>Immobilienobjekte verwalten</source> |
| 12 | 12 |
</trans-unit> |
| 13 |
+ <trans-unit id="MOD.managed_properties.0"> |
|
| 14 |
+ <source>Verwaltete Objekte</source> |
|
| 15 |
+ </trans-unit> |
|
| 16 |
+ <trans-unit id="MOD.managed_properties.1"> |
|
| 17 |
+ <source>Verwaltete Objekte pflegen.</source> |
|
| 18 |
+ </trans-unit> |
|
| 13 | 19 |
<trans-unit id="MOD.tl_vr_real_estate_categories"> |
| 14 | 20 |
<source>Objektkategorie</source> |
| 15 | 21 |
</trans-unit> |
| 16 | 22 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,96 @@ |
| 1 |
+<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 |
+<xliff version="1.1"> |
|
| 3 |
+ <file source-language="en" target-language="de"> |
|
| 4 |
+ <body> |
|
| 5 |
+ <trans-unit id="tl_vr_re_managedProperties.address.0"> |
|
| 6 |
+ <source>Address</source> |
|
| 7 |
+ <target>Adresse</target> |
|
| 8 |
+ </trans-unit> |
|
| 9 |
+ <trans-unit id="tl_vr_re_managedProperties.address.1"> |
|
| 10 |
+ <source>The address of the property.</source> |
|
| 11 |
+ <target>Die Adresse des Objekts.</target> |
|
| 12 |
+ </trans-unit> |
|
| 13 |
+ <trans-unit id="tl_vr_re_managedProperties.postal.0"> |
|
| 14 |
+ <source>Postal</source> |
|
| 15 |
+ <target>Postleitzahl</target> |
|
| 16 |
+ </trans-unit> |
|
| 17 |
+ <trans-unit id="tl_vr_re_managedProperties.postal.1"> |
|
| 18 |
+ <source>The postal of the property.</source> |
|
| 19 |
+ <target>Die Postleitzahl des Objekts.</target> |
|
| 20 |
+ </trans-unit> |
|
| 21 |
+ <trans-unit id="tl_vr_re_managedProperties.city.0"> |
|
| 22 |
+ <source>City</source> |
|
| 23 |
+ <target>Ort</target> |
|
| 24 |
+ </trans-unit> |
|
| 25 |
+ <trans-unit id="tl_vr_re_managedProperties.city.1"> |
|
| 26 |
+ <source>The name of the city where the property is situated.</source> |
|
| 27 |
+ <target>Der Name des Ortes, wo das Objekt steht.</target> |
|
| 28 |
+ </trans-unit> |
|
| 29 |
+ <trans-unit id="tl_vr_re_managedProperties.gallerySRC.0"> |
|
| 30 |
+ <source>Images</source> |
|
| 31 |
+ <target>Bilder</target> |
|
| 32 |
+ </trans-unit> |
|
| 33 |
+ <trans-unit id="tl_vr_re_managedProperties.gallerySRC.1"> |
|
| 34 |
+ <source>Select related images of the property in the file browser.</source> |
|
| 35 |
+ <target>Wählen Sie relevante Bilder zum Objekt aus dem Dateibrowser aus.</target> |
|
| 36 |
+ </trans-unit> |
|
| 37 |
+ <trans-unit id="tl_vr_re_managedProperties.description.0"> |
|
| 38 |
+ <source>Description</source> |
|
| 39 |
+ <target>Beschreibung</target> |
|
| 40 |
+ </trans-unit> |
|
| 41 |
+ <trans-unit id="tl_vr_re_managedProperties.description.1"> |
|
| 42 |
+ <source>A describing text about the property.</source> |
|
| 43 |
+ <target>Ein beschreibender Text zum Objekt.</target> |
|
| 44 |
+ </trans-unit> |
|
| 45 |
+ <trans-unit id="tl_vr_re_managedProperties.mapIframe.0"> |
|
| 46 |
+ <source>Map HTML</source> |
|
| 47 |
+ <target>Karten-HTML</target> |
|
| 48 |
+ </trans-unit> |
|
| 49 |
+ <trans-unit id="tl_vr_re_managedProperties.mapIframe.1"> |
|
| 50 |
+ <source>HTML snippet for the map to embed.</source> |
|
| 51 |
+ <target>HTML-Snippet für die einzubettende Karte.</target> |
|
| 52 |
+ </trans-unit> |
|
| 53 |
+ <trans-unit id="tl_vr_re_managedProperties.published.0"> |
|
| 54 |
+ <source>Publish</source> |
|
| 55 |
+ <target>Veröffentlichen</target> |
|
| 56 |
+ </trans-unit> |
|
| 57 |
+ <trans-unit id="tl_vr_re_managedProperties.published.1"> |
|
| 58 |
+ <source>The property is published on the website.</source> |
|
| 59 |
+ <target>Das Objekt wird auf der Webseite veröffentlicht.</target> |
|
| 60 |
+ </trans-unit> |
|
| 61 |
+ <trans-unit id="tl_vr_re_managedProperties.start.0"> |
|
| 62 |
+ <source>Publish from</source> |
|
| 63 |
+ <target>Anzeigen ab</target> |
|
| 64 |
+ </trans-unit> |
|
| 65 |
+ <trans-unit id="tl_vr_re_managedProperties.start.1"> |
|
| 66 |
+ <source>From when the object should be visible. Leave empty for immediate publication.</source> |
|
| 67 |
+ <target>Ab wann das Objekt sichtbar sein soll. Leer lassen für sofortige Veröffentlichung.</target> |
|
| 68 |
+ </trans-unit> |
|
| 69 |
+ <trans-unit id="tl_vr_re_managedProperties.stop.0"> |
|
| 70 |
+ <source>Publish until</source> |
|
| 71 |
+ <target>Anzeigen bis</target> |
|
| 72 |
+ </trans-unit> |
|
| 73 |
+ <trans-unit id="tl_vr_re_managedProperties.stop.1"> |
|
| 74 |
+ <source>Until when the object should be visible. Leave empty for permanent publication.</source> |
|
| 75 |
+ <target>Bis wann das Objekt sichtbar sein soll. Leer lassen für dauerhafte Veröffentlichung.</target> |
|
| 76 |
+ </trans-unit> |
|
| 77 |
+ |
|
| 78 |
+ <trans-unit id="tl_vr_re_managedProperties.data_legend"> |
|
| 79 |
+ <source>Basic data</source> |
|
| 80 |
+ <target>Grunddaten</target> |
|
| 81 |
+ </trans-unit> |
|
| 82 |
+ <trans-unit id="tl_vr_re_managedProperties.description_legend"> |
|
| 83 |
+ <source>Description</source> |
|
| 84 |
+ <target>Beschreibung</target> |
|
| 85 |
+ </trans-unit> |
|
| 86 |
+ <trans-unit id="tl_vr_re_managedProperties.map_legend"> |
|
| 87 |
+ <source>Map</source> |
|
| 88 |
+ <target>Karte</target> |
|
| 89 |
+ </trans-unit> |
|
| 90 |
+ <trans-unit id="tl_vr_re_managedProperties.publish_legend"> |
|
| 91 |
+ <source>Publishing settings</source> |
|
| 92 |
+ <target>Veröffentlichungs-Einstellungen</target> |
|
| 93 |
+ </trans-unit> |
|
| 94 |
+ </body> |
|
| 95 |
+ </file> |
|
| 96 |
+</xliff> |
|
| 0 | 97 |
\ No newline at end of file |
| 1 | 98 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,72 @@ |
| 1 |
+{% extends '@Contao/frontend_module/_base.html.twig' %}
|
|
| 2 |
+{% import "@ContaoCore/Image/Studio/_macros.html.twig" as studio %}
|
|
| 3 |
+ |
|
| 4 |
+{% block content %}
|
|
| 5 |
+ |
|
| 6 |
+ {% block filter %}
|
|
| 7 |
+ <div class="-padding content-background-wrapper"> |
|
| 8 |
+ <div class="content-background-wrapper-bg"> |
|
| 9 |
+ </div> |
|
| 10 |
+ |
|
| 11 |
+ <div class="content-background-wrapper-fg"> |
|
| 12 |
+ <div class="content-grid"> |
|
| 13 |
+ <div class="fragments"> |
|
| 14 |
+ <h5>{{ 'MSC.re_filter'|trans({}, 'contao_default') }}</h5>
|
|
| 15 |
+ <form class="assets-list-filter" hx-get="{{ pageUrl is defined ? pageUrl : '' }}" hx-push-url="false" hx-headers='{"VR-Ajax": "RePropertiesList"}' hx-trigger="change, submit" hx-target="closest .module-managed-property" hx-indicator="body" class="filter">
|
|
| 16 |
+ {% if filterOptions is defined and filterOptions is iterable %}
|
|
| 17 |
+ {% for key, options in filterOptions %}
|
|
| 18 |
+ <div class="filter-wrapper"> |
|
| 19 |
+ <select name="filter[{{ key }}]"{% if filter[key] is defined and filter[key] is not empty %} class="active"{% endif %}>
|
|
| 20 |
+ <option value="">{{ ('REF.re_filter.' ~ key)|trans({}, 'contao_default') }}</option>
|
|
| 21 |
+ {% for value, label in options %}
|
|
| 22 |
+ <option value="{{ value }}"{% if filter[key] is defined and filter[key] == value %} selected{% endif %}>{{ label }}</option>
|
|
| 23 |
+ {% endfor %}
|
|
| 24 |
+ </select> |
|
| 25 |
+ </div> |
|
| 26 |
+ {% endfor %}
|
|
| 27 |
+ {% endif %}
|
|
| 28 |
+ </form> |
|
| 29 |
+ </div> |
|
| 30 |
+ </div> |
|
| 31 |
+ </div> |
|
| 32 |
+ </div> |
|
| 33 |
+ {% endblock %}
|
|
| 34 |
+ |
|
| 35 |
+ {% block assets %}
|
|
| 36 |
+ <div class="assetList"> |
|
| 37 |
+ {% for item in assets %}
|
|
| 38 |
+ {% block item %}
|
|
| 39 |
+ <div class="asset re_asset_card"> |
|
| 40 |
+ {% if item.teaserFigure %}
|
|
| 41 |
+ {{- studio.figure(item.teaserFigure, { attr: { class: ('image_container media') }}) -}}
|
|
| 42 |
+ {% endif %}
|
|
| 43 |
+ |
|
| 44 |
+ <div class="details"> |
|
| 45 |
+ <ul> |
|
| 46 |
+ <li> |
|
| 47 |
+ <span class="label">Adresse:</span> |
|
| 48 |
+ {% if item.address is not empty %}{{ item.address }}<br>{% endif %}
|
|
| 49 |
+ {% if item.postal is not empty and item.city is not empty %}{{ item.postal }} {{ item.city }}<br>{% endif %}
|
|
| 50 |
+ </li> |
|
| 51 |
+ {% if item.livingSpace > 0 %}
|
|
| 52 |
+ <li> |
|
| 53 |
+ <span class="label">Wohnfläche:</span> |
|
| 54 |
+ {{ item.livingSpace|number_format(2, ',', '') }} m²
|
|
| 55 |
+ </li> |
|
| 56 |
+ {% endif %}
|
|
| 57 |
+ </ul> |
|
| 58 |
+ {% if item.detailsUrl %}
|
|
| 59 |
+ <p class="details-link"><a class="link" href="{{ item.detailsUrl }}">{{ 'MSC.more'|trans({}, 'contao_default') }}</a></p>
|
|
| 60 |
+ {% endif %}
|
|
| 61 |
+ </div> |
|
| 62 |
+ </div> |
|
| 63 |
+ {% endblock %}
|
|
| 64 |
+ {% endfor %}
|
|
| 65 |
+ </div> |
|
| 66 |
+ {% endblock %}
|
|
| 67 |
+ |
|
| 68 |
+ |
|
| 69 |
+ {% block overlay %}
|
|
| 70 |
+ <div class="assets-list-overlay"></div> |
|
| 71 |
+ {% endblock %}
|
|
| 72 |
+{% endblock %}
|
| 0 | 73 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,75 @@ |
| 1 |
+{% extends '@Contao/frontend_module/_base.html.twig' %}
|
|
| 2 |
+{% use "@Contao/component/_list.html.twig" %}
|
|
| 3 |
+{% use "@Contao/component/_figure.html.twig" %}
|
|
| 4 |
+ |
|
| 5 |
+{%- macro listEntry(label, value, options = {}) -%}
|
|
| 6 |
+ {%- set class = options.class|default({}) -%}
|
|
| 7 |
+ {%- set prepend = options.prepend|default({}) %}
|
|
| 8 |
+ {% set append = options.append|default({}) -%}
|
|
| 9 |
+ {% set strong = options.strong is defined and options.strong ? true : false %}
|
|
| 10 |
+ {% apply spaceless %}
|
|
| 11 |
+ {% if label and value %}
|
|
| 12 |
+ <li class="{% if class %}{{- class -}}{% endif %}{{- strong ? ' strong' : '' -}}">
|
|
| 13 |
+ <span class="label">{{- label -}}</span>
|
|
| 14 |
+ <span class="value">{% if prepend %}{{ prepend }}{% endif %}{{- value -}}{% if append %}{{ append }}{% endif %}</span>
|
|
| 15 |
+ </li> |
|
| 16 |
+ {% endif %}
|
|
| 17 |
+ {% endapply %}
|
|
| 18 |
+{%- endmacro -%}
|
|
| 19 |
+{%- macro backgroundWrapper_open(classes = '') -%}
|
|
| 20 |
+<div class="{{ classes ? classes ~ ' ' : '' }}content-background-wrapper">
|
|
| 21 |
+ <div class="content-background-wrapper-bg"> |
|
| 22 |
+ </div> |
|
| 23 |
+ <div class="content-background-wrapper-fg"> |
|
| 24 |
+ <div class="content-grid"> |
|
| 25 |
+ <div class="fragments"> |
|
| 26 |
+ {%- endmacro -%}
|
|
| 27 |
+ {%- macro backgroundWrapper_close() -%}
|
|
| 28 |
+ </div> |
|
| 29 |
+ </div> |
|
| 30 |
+ </div> |
|
| 31 |
+</div> |
|
| 32 |
+{%- endmacro -%}
|
|
| 33 |
+ |
|
| 34 |
+ |
|
| 35 |
+{% block content %}
|
|
| 36 |
+ {% import "@ContaoCore/Image/Studio/_macros.html.twig" as studio %}
|
|
| 37 |
+ |
|
| 38 |
+ <div class="re_asset_expose"> |
|
| 39 |
+ |
|
| 40 |
+ {{ _self.backgroundWrapper_open('-padding-medium') }}
|
|
| 41 |
+ <p class="overviewLink"><a class="btn btn-outline-primary" href="{{ item.listUrl }}">Zurück zur Übersicht</a></p>
|
|
| 42 |
+ <h1>{% if item.city %}{{ item.city }}{% endif %}{% if item.address %} {{ item.address }}{% endif %}</h1>
|
|
| 43 |
+ {{ _self.backgroundWrapper_close }}
|
|
| 44 |
+ |
|
| 45 |
+ {{ _self.backgroundWrapper_open('-alt-color-1 -padding-medium') }}
|
|
| 46 |
+ |
|
| 47 |
+ <div class="teaser-wrapper"> |
|
| 48 |
+ {% if item.teaserFigure %}
|
|
| 49 |
+ {{- studio.figure(item.teaserFigure, { attr: { class: ('image_container media') }}) -}}
|
|
| 50 |
+ {% endif %}
|
|
| 51 |
+ {% if item.map %}
|
|
| 52 |
+ {% block map %}<div class="map-embed">{{ item.map|default|insert_tag|raw }}</div>{% endblock %}
|
|
| 53 |
+ {% endif %}
|
|
| 54 |
+ </div> |
|
| 55 |
+ |
|
| 56 |
+ {% if item.description %}
|
|
| 57 |
+ <div class="description">{{ item.description|raw }}</div>
|
|
| 58 |
+ {% endif %}
|
|
| 59 |
+ |
|
| 60 |
+ <div class="expose-gallery"> |
|
| 61 |
+ {% with {items: item.galleryFigures} %}{{ block('list_component') }}{% endwith %}
|
|
| 62 |
+ </div> |
|
| 63 |
+ {{ _self.backgroundWrapper_close }}
|
|
| 64 |
+ |
|
| 65 |
+ {{ _self.backgroundWrapper_open('-padding') }}
|
|
| 66 |
+ <p class="overviewLink"><a class="btn btn-outline-primary" href="{{ item.listUrl }}">Zurück zur Übersicht</a></p>
|
|
| 67 |
+ {{ _self.backgroundWrapper_close }}
|
|
| 68 |
+ |
|
| 69 |
+ |
|
| 70 |
+ </div> |
|
| 71 |
+{% endblock %}
|
|
| 72 |
+ |
|
| 73 |
+{% block list_item %}
|
|
| 74 |
+ {% with {figure: item} %}{{ block('figure_component') }}{% endwith %}
|
|
| 75 |
+{% endblock %}
|
| 0 | 76 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,217 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+declare(strict_types=1); |
|
| 4 |
+ |
|
| 5 |
+namespace vonRotenberg\RealEstateListingBundle\Controller\FrontendModule; |
|
| 6 |
+ |
|
| 7 |
+use vonRotenberg\RealEstateListingBundle\Model\ManagedPropertyModel; |
|
| 8 |
+use Contao\ArrayUtil; |
|
| 9 |
+use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController; |
|
| 10 |
+use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule; |
|
| 11 |
+use Contao\CoreBundle\Exception\ResponseException; |
|
| 12 |
+use Contao\CoreBundle\Image\Studio\Figure; |
|
| 13 |
+use Contao\CoreBundle\Image\Studio\FigureBuilder; |
|
| 14 |
+use Contao\CoreBundle\Twig\FragmentTemplate; |
|
| 15 |
+use Contao\File; |
|
| 16 |
+use Contao\FilesModel; |
|
| 17 |
+use Contao\Input; |
|
| 18 |
+use Contao\ModuleModel; |
|
| 19 |
+use Contao\PageModel; |
|
| 20 |
+use Contao\StringUtil; |
|
| 21 |
+use Contao\System; |
|
| 22 |
+use Symfony\Component\HttpFoundation\Request; |
|
| 23 |
+use Symfony\Component\HttpFoundation\Response; |
|
| 24 |
+ |
|
| 25 |
+#[AsFrontendModule(category: 'vr_real_estate')] |
|
| 26 |
+class ManagedPropertyController extends AbstractFrontendModuleController |
|
| 27 |
+{
|
|
| 28 |
+ public const TYPE = 'managed_property'; |
|
| 29 |
+ protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response |
|
| 30 |
+ {
|
|
| 31 |
+ |
|
| 32 |
+ $arrAssets = []; |
|
| 33 |
+ $arrFilterOptions = [ |
|
| 34 |
+ 'city' => [] |
|
| 35 |
+ ]; |
|
| 36 |
+ $arrFilterSelected = []; |
|
| 37 |
+ $arrAssetsOptions = []; |
|
| 38 |
+ |
|
| 39 |
+ $jumpTo = PageModel::findByPk($model->jumpTo); |
|
| 40 |
+ $urlGenerator = System::getContainer()->get('contao.routing.content_url_generator');
|
|
| 41 |
+ |
|
| 42 |
+ // Filter |
|
| 43 |
+ if (isset($_GET['filter']) && \is_array(Input::get('filter')))
|
|
| 44 |
+ {
|
|
| 45 |
+ foreach (Input::get('filter') as $filter=>$value)
|
|
| 46 |
+ {
|
|
| 47 |
+ if (in_array($filter, array_keys($arrFilterOptions)) && !empty($value)) |
|
| 48 |
+ {
|
|
| 49 |
+ $rawValue = StringUtil::decodeEntities($value); |
|
| 50 |
+ $arrFilterSelected[$filter] = $rawValue; |
|
| 51 |
+ |
|
| 52 |
+ if (preg_match('/^.*<>.*$/',$rawValue))
|
|
| 53 |
+ {
|
|
| 54 |
+ list($start,$stop) = preg_split('/<>/',$rawValue, 2);
|
|
| 55 |
+ $arrAssetsOptions['column'][$filter] = "$filter BETWEEN $start AND $stop"; |
|
| 56 |
+ } else {
|
|
| 57 |
+ $arrAssetsOptions['column'][$filter] = "$filter = ?"; |
|
| 58 |
+ $arrAssetsOptions['value'][$filter] = $rawValue; |
|
| 59 |
+ } |
|
| 60 |
+ } |
|
| 61 |
+ } |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ if (($assets = ManagedPropertyModel::findAllPublished(0,0,$arrAssetsOptions)) === null) |
|
| 65 |
+ {
|
|
| 66 |
+ return $template->getResponse(); |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ // Figure Builder |
|
| 70 |
+ $figureBuilder = System::getContainer() |
|
| 71 |
+ ->get('contao.image.studio')
|
|
| 72 |
+ ->createFigureBuilder() |
|
| 73 |
+ ->setSize($model->imgSize) |
|
| 74 |
+ ->setLightboxGroupIdentifier('lb' . $model->id);
|
|
| 75 |
+ |
|
| 76 |
+ foreach ($assets as $asset) |
|
| 77 |
+ {
|
|
| 78 |
+ $arrItem = array_merge($asset->row(), [ |
|
| 79 |
+ 'teaserFigure' => $this->getImageFigures($asset->gallerySRC, $figureBuilder, $asset->orderSRC, 1), |
|
| 80 |
+ 'detailsUrl' => $jumpTo !== null ? $urlGenerator->generate($jumpTo, ['parameters'=>'/items/'.$asset->id]) : null |
|
| 81 |
+ ]); |
|
| 82 |
+ |
|
| 83 |
+ $arrAssets[] = $arrItem; |
|
| 84 |
+ } |
|
| 85 |
+ |
|
| 86 |
+ // Populate filters |
|
| 87 |
+ $filterAssets = ManagedPropertyModel::findAllPublished(); |
|
| 88 |
+ foreach ($filterAssets as $asset) |
|
| 89 |
+ {
|
|
| 90 |
+ // Filter options |
|
| 91 |
+ if (!empty($asset->city)) |
|
| 92 |
+ {
|
|
| 93 |
+ $tmpOptions = $arrAssetsOptions; |
|
| 94 |
+ $tmpOptions['column'] = array_merge((isset($arrAssetsOptions['column']) ? $arrAssetsOptions['column'] : []),['city'=>'city = ?']); |
|
| 95 |
+ $tmpOptions['value'] = array_merge((isset($arrAssetsOptions['value']) ? $arrAssetsOptions['value'] : []),['city'=>$asset->city]); |
|
| 96 |
+ $count = ManagedPropertyModel::countAllPublished($tmpOptions); |
|
| 97 |
+ $arrFilterOptions['city'][$asset->city] = $asset->city . ' ('.$count.')';
|
|
| 98 |
+ } |
|
| 99 |
+ } |
|
| 100 |
+ |
|
| 101 |
+ foreach (array_keys($arrFilterOptions) as $filterName) |
|
| 102 |
+ {
|
|
| 103 |
+ $arrFilterOptions[$filterName] = array_unique($arrFilterOptions[$filterName]); |
|
| 104 |
+ } |
|
| 105 |
+ |
|
| 106 |
+ // Set template data |
|
| 107 |
+ $template->set('filterOptions',$arrFilterOptions);
|
|
| 108 |
+ $template->set('filter',$arrFilterSelected);
|
|
| 109 |
+ $template->set('assets',$arrAssets);
|
|
| 110 |
+ |
|
| 111 |
+ // Handle ajax |
|
| 112 |
+ if ($request->headers->get('VR-Ajax') == 'RePropertiesList')
|
|
| 113 |
+ {
|
|
| 114 |
+ throw new ResponseException($template->getResponse()); |
|
| 115 |
+ } |
|
| 116 |
+ |
|
| 117 |
+ return $template->getResponse(); |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+ /** |
|
| 121 |
+ * @param string|array $strUuids |
|
| 122 |
+ * @param FigureBuilder $figureBuilder |
|
| 123 |
+ * @param string|array $strOrder |
|
| 124 |
+ * |
|
| 125 |
+ * @return array|Figure |
|
| 126 |
+ * @throws \Exception |
|
| 127 |
+ */ |
|
| 128 |
+ public function getImageFigures($strUuids, $figureBuilder, $strOrder = null, int $intLimit = 0, int $intOffset = 0) |
|
| 129 |
+ {
|
|
| 130 |
+ $arrImageFigures = []; |
|
| 131 |
+ |
|
| 132 |
+ if (($imageFiles = FilesModel::findMultipleByUuids(StringUtil::deserialize($strUuids))) !== null) |
|
| 133 |
+ {
|
|
| 134 |
+ $images = array(); |
|
| 135 |
+ while ($imageFiles->next()) |
|
| 136 |
+ {
|
|
| 137 |
+ // Continue if the files has been processed or does not exist |
|
| 138 |
+ if (isset($images[$imageFiles->path]) || !file_exists(System::getContainer()->getParameter('kernel.project_dir') . '/' . $imageFiles->path))
|
|
| 139 |
+ {
|
|
| 140 |
+ continue; |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ // Single files |
|
| 144 |
+ if ($imageFiles->type == 'file') |
|
| 145 |
+ {
|
|
| 146 |
+ $objFile = new File($imageFiles->path); |
|
| 147 |
+ |
|
| 148 |
+ if (!$objFile->isImage) |
|
| 149 |
+ {
|
|
| 150 |
+ continue; |
|
| 151 |
+ } |
|
| 152 |
+ |
|
| 153 |
+ // Add the image |
|
| 154 |
+ $images[$imageFiles->path] = $imageFiles->current(); |
|
| 155 |
+ } // Folders |
|
| 156 |
+ else |
|
| 157 |
+ {
|
|
| 158 |
+ $objSubfiles = FilesModel::findByPid($imageFiles->uuid, array('order' => 'name'));
|
|
| 159 |
+ |
|
| 160 |
+ if ($objSubfiles === null) |
|
| 161 |
+ {
|
|
| 162 |
+ continue; |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ while ($objSubfiles->next()) |
|
| 166 |
+ {
|
|
| 167 |
+ // Skip subfolders |
|
| 168 |
+ if ($objSubfiles->type == 'folder') |
|
| 169 |
+ {
|
|
| 170 |
+ continue; |
|
| 171 |
+ } |
|
| 172 |
+ |
|
| 173 |
+ $objFile = new File($objSubfiles->path); |
|
| 174 |
+ |
|
| 175 |
+ if (!$objFile->isImage) |
|
| 176 |
+ {
|
|
| 177 |
+ continue; |
|
| 178 |
+ } |
|
| 179 |
+ |
|
| 180 |
+ // Add the image |
|
| 181 |
+ $images[$objSubfiles->path] = $objSubfiles->current(); |
|
| 182 |
+ } |
|
| 183 |
+ } |
|
| 184 |
+ } |
|
| 185 |
+ |
|
| 186 |
+ if ($strOrder !== null) |
|
| 187 |
+ {
|
|
| 188 |
+ $images = ArrayUtil::sortByOrderField($images, $strOrder); |
|
| 189 |
+ } |
|
| 190 |
+ $images = array_values($images); |
|
| 191 |
+ |
|
| 192 |
+ // Offset images |
|
| 193 |
+ if ($intOffset > 0) |
|
| 194 |
+ {
|
|
| 195 |
+ $images = \array_slice($images, ($intOffset < count($images) ? $intOffset : count($images))); |
|
| 196 |
+ } |
|
| 197 |
+ |
|
| 198 |
+ // Limit number of images |
|
| 199 |
+ if ($intLimit > 0) |
|
| 200 |
+ {
|
|
| 201 |
+ $images = \array_slice($images, 0, $intLimit); |
|
| 202 |
+ } |
|
| 203 |
+ |
|
| 204 |
+ // Build figures of images |
|
| 205 |
+ foreach ($images as $image) |
|
| 206 |
+ {
|
|
| 207 |
+ $figure = $figureBuilder |
|
| 208 |
+ ->fromFilesModel($image) |
|
| 209 |
+ ->build(); |
|
| 210 |
+ |
|
| 211 |
+ $arrImageFigures[] = $figure; |
|
| 212 |
+ } |
|
| 213 |
+ |
|
| 214 |
+ } |
|
| 215 |
+ return count ($arrImageFigures) === 1 && $intLimit === 1 ? array_shift($arrImageFigures) : $arrImageFigures; |
|
| 216 |
+ } |
|
| 217 |
+} |
| 0 | 218 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,187 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+declare(strict_types=1); |
|
| 4 |
+ |
|
| 5 |
+namespace vonRotenberg\RealEstateListingBundle\Controller\FrontendModule; |
|
| 6 |
+ |
|
| 7 |
+use vonRotenberg\RealEstateListingBundle\Model\ManagedPropertyModel; |
|
| 8 |
+use Contao\ArrayUtil; |
|
| 9 |
+use Contao\Controller; |
|
| 10 |
+use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController; |
|
| 11 |
+use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule; |
|
| 12 |
+use Contao\CoreBundle\Exception\ResponseException; |
|
| 13 |
+use Contao\CoreBundle\Image\Studio\Figure; |
|
| 14 |
+use Contao\CoreBundle\Image\Studio\FigureBuilder; |
|
| 15 |
+use Contao\CoreBundle\Twig\FragmentTemplate; |
|
| 16 |
+use Contao\Date; |
|
| 17 |
+use Contao\File; |
|
| 18 |
+use Contao\FilesModel; |
|
| 19 |
+use Contao\FrontendTemplate; |
|
| 20 |
+use Contao\Input; |
|
| 21 |
+use Contao\ModuleModel; |
|
| 22 |
+use Contao\PageModel; |
|
| 23 |
+use Contao\StringUtil; |
|
| 24 |
+use Contao\System; |
|
| 25 |
+use Contao\Template; |
|
| 26 |
+use Symfony\Component\HttpFoundation\Request; |
|
| 27 |
+use Symfony\Component\HttpFoundation\Response; |
|
| 28 |
+use Symfony\Contracts\Translation\TranslatorInterface; |
|
| 29 |
+use vonRotenberg\RealEstateListingBundle\Model\RealEstateAssetsModel; |
|
| 30 |
+ |
|
| 31 |
+#[AsFrontendModule(category: 'vr_real_estate')] |
|
| 32 |
+class ManagedPropertyReaderController extends AbstractFrontendModuleController |
|
| 33 |
+{
|
|
| 34 |
+ public const TYPE = 'managed_property_reader'; |
|
| 35 |
+ /** |
|
| 36 |
+ * @var RealEstateAssetsModel|null |
|
| 37 |
+ */ |
|
| 38 |
+ protected $asset; |
|
| 39 |
+ |
|
| 40 |
+ /** |
|
| 41 |
+ * @var TranslatorInterface |
|
| 42 |
+ */ |
|
| 43 |
+ protected $translator; |
|
| 44 |
+ |
|
| 45 |
+ protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response |
|
| 46 |
+ {
|
|
| 47 |
+ $this->translator = System::getContainer()->get('translator');
|
|
| 48 |
+ Controller::loadLanguageFile(ManagedPropertyModel::getTable()); |
|
| 49 |
+ |
|
| 50 |
+ $jumpTo = PageModel::findByPk($model->jumpTo); |
|
| 51 |
+ |
|
| 52 |
+ // Set the item from the auto_item parameter |
|
| 53 |
+ if (!isset($_GET['items']) && \Config::get('useAutoItem') && isset($_GET['auto_item']))
|
|
| 54 |
+ {
|
|
| 55 |
+ Input::setGet('items', Input::get('auto_item'));
|
|
| 56 |
+ } |
|
| 57 |
+ |
|
| 58 |
+ $this->asset = ManagedPropertyModel::findPublishedByIdOrAlias(Input::get('items'));
|
|
| 59 |
+ |
|
| 60 |
+ if ($this->asset === null) |
|
| 61 |
+ {
|
|
| 62 |
+ return new Response(); |
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ $figureBuilder = System::getContainer() |
|
| 66 |
+ ->get('contao.image.studio')
|
|
| 67 |
+ ->createFigureBuilder() |
|
| 68 |
+ ->setSize($model->imgSize) |
|
| 69 |
+ ->enableLightbox(true); |
|
| 70 |
+// ->setLightboxGroupIdentifier('lb' . $model->id);
|
|
| 71 |
+ |
|
| 72 |
+ $arrItem = array_merge($this->asset->row(), [ |
|
| 73 |
+ 'features' => StringUtil::deserialize($this->asset->features,true), |
|
| 74 |
+ 'availableFrom' => ($this->asset->availability == 'immediately' ? $this->translator->trans('REF.re_availability.immediately', [], 'contao_default') : Date::parse(Date::getNumericDateFormat(), $this->asset->availableFrom)),
|
|
| 75 |
+ 'deadline' => ($this->asset->stop > 0 ? Date::parse(Date::getNumericDateFormat(), $this->asset->stop) : ''), |
|
| 76 |
+ 'teaserFigure' => $this->getImageFigures($this->asset->gallerySRC, $figureBuilder, $this->asset->orderSRC, 1), |
|
| 77 |
+ 'galleryFigures' => $this->getImageFigures($this->asset->gallerySRC, $figureBuilder, $this->asset->orderSRC, 0, 0), |
|
| 78 |
+ 'floorPlansFigures' => $this->getImageFigures($this->asset->floorPlansSRC, $figureBuilder, $this->asset->floorPlansOrderSRC), |
|
| 79 |
+ 'listUrl' => $jumpTo !== null ? $jumpTo->getFrontendUrl() : null, |
|
| 80 |
+ 'pdfUrl' => $request->getBaseUrl() . $request->getPathInfo() . '?pdf', |
|
| 81 |
+ 'qrUrl' => $request->getUriForPath($request->getPathInfo()), |
|
| 82 |
+ 'map' => $this->asset->mapIframe ?? '' |
|
| 83 |
+ ]); |
|
| 84 |
+ |
|
| 85 |
+ $template->item = $arrItem; |
|
| 86 |
+ |
|
| 87 |
+ return $template->getResponse(); |
|
| 88 |
+ } |
|
| 89 |
+ |
|
| 90 |
+ /** |
|
| 91 |
+ * @param string|array $strUuids |
|
| 92 |
+ * @param FigureBuilder $figureBuilder |
|
| 93 |
+ * @param string|array $strOrder |
|
| 94 |
+ * |
|
| 95 |
+ * @return array|Figure |
|
| 96 |
+ * @throws \Exception |
|
| 97 |
+ */ |
|
| 98 |
+ public function getImageFigures($strUuids, $figureBuilder, $strOrder = null, int $intLimit = 0, int $intOffset = 0) |
|
| 99 |
+ {
|
|
| 100 |
+ $arrImageFigures = []; |
|
| 101 |
+ |
|
| 102 |
+ if (($imageFiles = FilesModel::findMultipleByUuids(StringUtil::deserialize($strUuids))) !== null) |
|
| 103 |
+ {
|
|
| 104 |
+ $images = array(); |
|
| 105 |
+ while ($imageFiles->next()) |
|
| 106 |
+ {
|
|
| 107 |
+ // Continue if the files has been processed or does not exist |
|
| 108 |
+ if (isset($images[$imageFiles->path]) || !file_exists(System::getContainer()->getParameter('kernel.project_dir') . '/' . $imageFiles->path))
|
|
| 109 |
+ {
|
|
| 110 |
+ continue; |
|
| 111 |
+ } |
|
| 112 |
+ |
|
| 113 |
+ // Single files |
|
| 114 |
+ if ($imageFiles->type == 'file') |
|
| 115 |
+ {
|
|
| 116 |
+ $objFile = new File($imageFiles->path); |
|
| 117 |
+ |
|
| 118 |
+ if (!$objFile->isImage) |
|
| 119 |
+ {
|
|
| 120 |
+ continue; |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 123 |
+ // Add the image |
|
| 124 |
+ $images[$imageFiles->path] = $imageFiles->current(); |
|
| 125 |
+ } // Folders |
|
| 126 |
+ else |
|
| 127 |
+ {
|
|
| 128 |
+ $objSubfiles = FilesModel::findByPid($imageFiles->uuid, array('order' => 'name'));
|
|
| 129 |
+ |
|
| 130 |
+ if ($objSubfiles === null) |
|
| 131 |
+ {
|
|
| 132 |
+ continue; |
|
| 133 |
+ } |
|
| 134 |
+ |
|
| 135 |
+ while ($objSubfiles->next()) |
|
| 136 |
+ {
|
|
| 137 |
+ // Skip subfolders |
|
| 138 |
+ if ($objSubfiles->type == 'folder') |
|
| 139 |
+ {
|
|
| 140 |
+ continue; |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ $objFile = new File($objSubfiles->path); |
|
| 144 |
+ |
|
| 145 |
+ if (!$objFile->isImage) |
|
| 146 |
+ {
|
|
| 147 |
+ continue; |
|
| 148 |
+ } |
|
| 149 |
+ |
|
| 150 |
+ // Add the image |
|
| 151 |
+ $images[$objSubfiles->path] = $objSubfiles->current(); |
|
| 152 |
+ } |
|
| 153 |
+ } |
|
| 154 |
+ } |
|
| 155 |
+ |
|
| 156 |
+ if ($strOrder !== null) |
|
| 157 |
+ {
|
|
| 158 |
+ $images = ArrayUtil::sortByOrderField($images, $strOrder); |
|
| 159 |
+ } |
|
| 160 |
+ $images = array_values($images); |
|
| 161 |
+ |
|
| 162 |
+ // Offset images |
|
| 163 |
+ if ($intOffset > 0) |
|
| 164 |
+ {
|
|
| 165 |
+ $images = \array_slice($images, ($intOffset < count($images) ? $intOffset : count($images))); |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 168 |
+ // Limit number of images |
|
| 169 |
+ if ($intLimit > 0) |
|
| 170 |
+ {
|
|
| 171 |
+ $images = \array_slice($images, 0, $intLimit); |
|
| 172 |
+ } |
|
| 173 |
+ |
|
| 174 |
+ // Build figures of images |
|
| 175 |
+ foreach ($images as $image) |
|
| 176 |
+ {
|
|
| 177 |
+ $figure = $figureBuilder |
|
| 178 |
+ ->fromFilesModel($image) |
|
| 179 |
+ ->build(); |
|
| 180 |
+ |
|
| 181 |
+ $arrImageFigures[] = $figure; |
|
| 182 |
+ } |
|
| 183 |
+ |
|
| 184 |
+ } |
|
| 185 |
+ return count ($arrImageFigures) === 1 && $intLimit === 1 ? array_shift($arrImageFigures) : $arrImageFigures; |
|
| 186 |
+ } |
|
| 187 |
+} |
| 0 | 188 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,178 @@ |
| 1 |
+<?php |
|
| 2 |
+ |
|
| 3 |
+/** |
|
| 4 |
+ * OBG Customizations |
|
| 5 |
+ * |
|
| 6 |
+ * Copyright (c) 2021 vonRotenberg |
|
| 7 |
+ * |
|
| 8 |
+ * @license commercial |
|
| 9 |
+ */ |
|
| 10 |
+ |
|
| 11 |
+namespace vonRotenberg\RealEstateListingBundle\Model; |
|
| 12 |
+ |
|
| 13 |
+use Contao\Date; |
|
| 14 |
+use Contao\Model; |
|
| 15 |
+use Contao\Model\Collection; |
|
| 16 |
+ |
|
| 17 |
+/** |
|
| 18 |
+ * Reads and writes assets |
|
| 19 |
+ * |
|
| 20 |
+ * @property string|integer $id |
|
| 21 |
+ * @property string|integer $tstamp |
|
| 22 |
+ * @property string $address |
|
| 23 |
+ * @property string $postal |
|
| 24 |
+ * @property string $city |
|
| 25 |
+ * @property string|null $gallerySRC |
|
| 26 |
+ * @property string|null $orderSRC |
|
| 27 |
+ * @property string|null $description |
|
| 28 |
+ * @property string|boolean $published |
|
| 29 |
+ * @property string|integer $start |
|
| 30 |
+ * @property string|integer $stop |
|
| 31 |
+ * |
|
| 32 |
+ * @method static ManagedPropertyModel|null findById($id, array $opt = array()) |
|
| 33 |
+ * @method static ManagedPropertyModel|null findByPk($id, array $opt = array()) |
|
| 34 |
+ * @method static ManagedPropertyModel|null findOneBy($col, $val, array $opt = array()) |
|
| 35 |
+ * @method static ManagedPropertyModel|null findOneByTstamp($val, array $opt = array()) |
|
| 36 |
+ * @method static ManagedPropertyModel|null findOneByAddress($val, array $opt = array()) |
|
| 37 |
+ * @method static ManagedPropertyModel|null findOneByPostal($val, array $opt = array()) |
|
| 38 |
+ * @method static ManagedPropertyModel|null findOneByCity($val, array $opt = array()) |
|
| 39 |
+ * @method static ManagedPropertyModel|null findOneByGallerySRC($val, array $opt = array()) |
|
| 40 |
+ * @method static ManagedPropertyModel|null findOneByDescription($val, array $opt = array()) |
|
| 41 |
+ * @method static ManagedPropertyModel|null findOneByPublished($val, array $opt = array()) |
|
| 42 |
+ * @method static ManagedPropertyModel|null findOneByStart($val, array $opt = array()) |
|
| 43 |
+ * @method static ManagedPropertyModel|null findOneByStop($val, array $opt = array()) |
|
| 44 |
+ * |
|
| 45 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByTstamp($val, array $opt = array()) |
|
| 46 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByAddress($val, array $opt = array()) |
|
| 47 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByPostal($val, array $opt = array()) |
|
| 48 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByCity($val, array $opt = array()) |
|
| 49 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByGallerySRC($val, array $opt = array()) |
|
| 50 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByDescription($val, array $opt = array()) |
|
| 51 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByPublished($val, array $opt = array()) |
|
| 52 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByStart($val, array $opt = array()) |
|
| 53 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findByStop($val, array $opt = array()) |
|
| 54 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findMultipleByIds($val, array $opt = array()) |
|
| 55 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findBy($col, $val, array $opt = array()) |
|
| 56 |
+ * @method static Collection|ManagedPropertyModel[]|ManagedPropertyModel|null findAll(array $opt = array()) |
|
| 57 |
+ * |
|
| 58 |
+ * @method static integer countById($id, array $opt = array()) |
|
| 59 |
+ * @method static integer countByTstamp($val, array $opt = array()) |
|
| 60 |
+ * @method static integer countByAddress($val, array $opt = array()) |
|
| 61 |
+ * @method static integer countByPostal($val, array $opt = array()) |
|
| 62 |
+ * @method static integer countByCity($val, array $opt = array()) |
|
| 63 |
+ * @method static integer countByGallerySRC($val, array $opt = array()) |
|
| 64 |
+ * @method static integer countByDescription($val, array $opt = array()) |
|
| 65 |
+ * @method static integer countByPublished($val, array $opt = array()) |
|
| 66 |
+ * @method static integer countByStart($val, array $opt = array()) |
|
| 67 |
+ * @method static integer countByStop($val, array $opt = array()) |
|
| 68 |
+ * |
|
| 69 |
+ * @author Benjamin Roth <https://www.vonrotenberg.de> |
|
| 70 |
+ */ |
|
| 71 |
+class ManagedPropertyModel extends Model |
|
| 72 |
+{
|
|
| 73 |
+ |
|
| 74 |
+ /** |
|
| 75 |
+ * Table name |
|
| 76 |
+ * @var string |
|
| 77 |
+ */ |
|
| 78 |
+ protected static $strTable = 'tl_vr_re_managedProperties'; |
|
| 79 |
+ |
|
| 80 |
+ /** |
|
| 81 |
+ * Find a published assets from one or more categories |
|
| 82 |
+ * |
|
| 83 |
+ * @param mixed $varId The numeric id or alias name |
|
| 84 |
+ * @param array $arrOptions An optional options array |
|
| 85 |
+ * |
|
| 86 |
+ * @return ManagedPropertyModel|null A model or null if there is no asset |
|
| 87 |
+ */ |
|
| 88 |
+ public static function findPublishedByIdOrAlias($varId, array $arrOptions = array()) |
|
| 89 |
+ {
|
|
| 90 |
+ $t = static::$strTable; |
|
| 91 |
+ $arrColumns = !preg_match('/^[1-9]\d*$/', $varId) ? array("BINARY $t.alias=?") : array("$t.id=?");
|
|
| 92 |
+ |
|
| 93 |
+ if (!static::isPreviewMode($arrOptions)) |
|
| 94 |
+ {
|
|
| 95 |
+ $time = Date::floorToMinute(); |
|
| 96 |
+ $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')"; |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ return static::findOneBy($arrColumns, $varId, $arrOptions); |
|
| 100 |
+ } |
|
| 101 |
+ |
|
| 102 |
+ /** |
|
| 103 |
+ * Find a published assets from one or more categories |
|
| 104 |
+ * |
|
| 105 |
+ * @param array $arrPids An array of parent IDs |
|
| 106 |
+ * @param integer $intLimit An optional limit |
|
| 107 |
+ * @param integer $intOffset An optional offset |
|
| 108 |
+ * @param array $arrOptions An optional options array |
|
| 109 |
+ * |
|
| 110 |
+ * @return Collection|ManagedPropertyModel[]|ManagedPropertyModel|null A collection of models or null if there are no assets |
|
| 111 |
+ */ |
|
| 112 |
+ public static function findAllPublished($intLimit = 0, $intOffset = 0, array $arrOptions = array()) |
|
| 113 |
+ {
|
|
| 114 |
+ $t = static::$strTable; |
|
| 115 |
+ $arrColumns = []; |
|
| 116 |
+ $arrValues = []; |
|
| 117 |
+ |
|
| 118 |
+ if (!static::isPreviewMode($arrOptions)) |
|
| 119 |
+ {
|
|
| 120 |
+ $time = Date::floorToMinute(); |
|
| 121 |
+ $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')"; |
|
| 122 |
+ } |
|
| 123 |
+ |
|
| 124 |
+ if (!isset($arrOptions['order'])) |
|
| 125 |
+ {
|
|
| 126 |
+ $arrOptions['order'] = "$t.city ASC, $t.livingSpace ASC"; |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ $arrOptions['limit'] = $intLimit; |
|
| 130 |
+ $arrOptions['offset'] = $intOffset; |
|
| 131 |
+ |
|
| 132 |
+ if (isset($arrOptions['column'])) |
|
| 133 |
+ {
|
|
| 134 |
+ $arrColumns = array_merge($arrColumns,array_values($arrOptions['column'])); |
|
| 135 |
+ unset($arrOptions['column']); |
|
| 136 |
+ } |
|
| 137 |
+ if (isset($arrOptions['value'])) |
|
| 138 |
+ {
|
|
| 139 |
+ $arrValues = array_merge($arrValues,array_values($arrOptions['value'])); |
|
| 140 |
+ unset($arrOptions['value']); |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ return static::findBy($arrColumns, $arrValues, $arrOptions); |
|
| 144 |
+ } |
|
| 145 |
+ |
|
| 146 |
+ /** |
|
| 147 |
+ * Find a published assets from one or more categories |
|
| 148 |
+ * |
|
| 149 |
+ * @param array $arrPids An array of parent IDs |
|
| 150 |
+ * @param array $arrOptions An optional options array |
|
| 151 |
+ * |
|
| 152 |
+ * @return integer The number of matching rows |
|
| 153 |
+ */ |
|
| 154 |
+ public static function countAllPublished(array $arrOptions = array()) |
|
| 155 |
+ {
|
|
| 156 |
+ $t = static::$strTable; |
|
| 157 |
+ $arrColumns = []; |
|
| 158 |
+ $arrValues = []; |
|
| 159 |
+ |
|
| 160 |
+ if (!static::isPreviewMode($arrOptions)) |
|
| 161 |
+ {
|
|
| 162 |
+ $time = Date::floorToMinute(); |
|
| 163 |
+ $arrColumns[] = "$t.published='1' AND ($t.start='' OR $t.start<='$time') AND ($t.stop='' OR $t.stop>'$time')"; |
|
| 164 |
+ } |
|
| 165 |
+ |
|
| 166 |
+ if (isset($arrOptions['column'])) |
|
| 167 |
+ {
|
|
| 168 |
+ $arrColumns = array_merge($arrColumns,array_values($arrOptions['column'])); |
|
| 169 |
+ unset($arrOptions['column']); |
|
| 170 |
+ } |
|
| 171 |
+ if (isset($arrOptions['value'])) |
|
| 172 |
+ {
|
|
| 173 |
+ $arrValues = array_merge($arrValues,array_values($arrOptions['value'])); |
|
| 174 |
+ unset($arrOptions['value']); |
|
| 175 |
+ } |
|
| 176 |
+ return static::countBy($arrColumns, $arrValues, $arrOptions); |
|
| 177 |
+ } |
|
| 178 |
+} |