@@ -1694,14 +1694,14 @@ public function widgetSetRegion(Request $request, Response $response, $id)
16941694 * @param Request $request
16951695 * @param Response $response
16961696 * @param $id
1697- * @return \Psr\Http\Message\ResponseInterface|Response
1698- * @throws AccessDeniedException
1699- * @throws GeneralException
1700- * @throws InvalidArgumentException
1701- * @throws NotFoundException
1697+ * @return \Slim\Http\Response
1698+ * @throws \Xibo\Support\Exception\AccessDeniedException
17021699 * @throws \Xibo\Support\Exception\ControllerNotImplemented
1700+ * @throws \Xibo\Support\Exception\GeneralException
1701+ * @throws \Xibo\Support\Exception\InvalidArgumentException
1702+ * @throws \Xibo\Support\Exception\NotFoundException
17031703 */
1704- public function saveElements (Request $ request , Response $ response , $ id )
1704+ public function saveElements (Request $ request , Response $ response , $ id ): Response
17051705 {
17061706 $ widget = $ this ->widgetFactory ->getById ($ id );
17071707 if (!$ this ->getUser ()->checkEditable ($ widget )) {
@@ -1747,20 +1747,39 @@ public function saveElements(Request $request, Response $response, $id)
17471747 );
17481748 }
17491749
1750- // Parse the element JSON to see if we need to set `itemsPerPage`
1750+ // Parse the element JSON
17511751 $ slots = [];
17521752 $ uniqueSlots = 0 ;
17531753 $ isMediaOnlyWidget = true ;
17541754 $ maxDuration = 1 ;
17551755
1756- foreach ($ elementJson as $ widgetElement ) {
1757- foreach ($ widgetElement ['elements ' ] ?? [] as $ element ) {
1756+ foreach ($ elementJson as $ widgetIndex => $ widgetElement ) {
1757+ foreach ($ widgetElement ['elements ' ] ?? [] as $ elementIndex => $ element ) {
1758+ $ this ->getLog ()->debug ('saveElements: processing widget index ' . $ widgetIndex
1759+ . ', element index ' . $ elementIndex . ' with id ' . $ element ['id ' ]);
1760+
17581761 $ slotNo = 'slot_ ' . ($ element ['slot ' ] ?? 0 );
17591762 if (!in_array ($ slotNo , $ slots )) {
17601763 $ slots [] = $ slotNo ;
17611764 $ uniqueSlots ++;
17621765 }
17631766
1767+ // Handle some of the common properties.
1768+ $ elementParams = $ this ->getSanitizer ([
1769+ 'elementName ' => $ element ['elementName ' ],
1770+ ]);
1771+ $ groupParams = $ this ->getSanitizer ($ element ['groupProperties ' ] ?? []);
1772+
1773+ // Reassert safely
1774+ // TODO: we should parse out all of the fields available in the JSON provided.
1775+ $ elementJson [$ widgetIndex ]['elements ' ][$ elementIndex ]['elementName ' ]
1776+ = $ elementParams ->getString ('elementName ' );
1777+ $ elementGroupName = $ groupParams ->getString ('elementGroupName ' );
1778+ if (!empty ($ elementGroupName )) {
1779+ $ elementJson [$ widgetIndex ]['elements ' ][$ elementIndex ]['groupProperties ' ]['elementGroupName ' ]
1780+ = $ elementGroupName ;
1781+ }
1782+
17641783 // Handle elements with the mediaId property so that media is linked and unlinked correctly.
17651784 if (!empty ($ element ['mediaId ' ])) {
17661785 $ mediaId = intval ($ element ['mediaId ' ]);
@@ -1776,14 +1795,69 @@ public function saveElements(Request $request, Response $response, $id)
17761795 $ isMediaOnlyWidget = false ;
17771796 }
17781797
1779- // Temporary workaround to process properties from the mediaSelector component when used by elements
1780- foreach ($ element ['properties ' ] ?? [] as $ property ) {
1781- if (!empty ($ property ['mediaId ' ])) {
1782- $ mediaId = intval ($ property ['mediaId ' ]);
1783- $ widget ->assignMedia ($ mediaId );
1784- $ newMediaIds [] = $ mediaId ;
1798+ // Get this elements template
1799+ $ elementTemplate = $ this ->moduleTemplateFactory ->getByTypeAndId ('element ' , $ element ['id ' ]);
1800+
1801+ // Does this template extend another? if so combine their properties
1802+ if ($ elementTemplate ->extends !== null ) {
1803+ $ extendedTemplate = $ this ->moduleTemplateFactory ->getByTypeAndId (
1804+ 'element ' ,
1805+ $ elementTemplate ->extends ->template ,
1806+ );
1807+
1808+ $ elementTemplate ->properties = array_merge (
1809+ $ elementTemplate ->properties ,
1810+ $ extendedTemplate ->properties
1811+ );
1812+ }
1813+
1814+ // Process element properties.
1815+ // Switch from {id:'',value:''} to key/value
1816+ $ elementPropertyParams = [];
1817+ foreach (($ element ['properties ' ] ?? []) as $ elementProperty ) {
1818+ $ elementPropertyParams [$ elementProperty ['id ' ]] = $ elementProperty ['value ' ] ?? null ;
1819+ }
1820+
1821+ $ this ->getLog ()->debug ('saveElements: parsed ' . count ($ elementPropertyParams )
1822+ . ' properties from request, there are ' . count ($ elementTemplate ->properties )
1823+ . ' properties defined in the template ' );
1824+
1825+ // Load into a sanitizer
1826+ $ elementProperties = $ this ->getSanitizer ($ elementPropertyParams );
1827+
1828+ // Process each property against its definition
1829+ foreach ($ elementTemplate ->properties as $ property ) {
1830+ if ($ property ->type === 'message ' ) {
1831+ continue ;
1832+ }
1833+ $ property ->setValueByType ($ elementProperties );
1834+
1835+ // Process properties from the mediaSelector component
1836+ if ($ property ->type === 'mediaSelector ' ) {
1837+ if (!empty ($ property ->value ) && is_numeric ($ property ->value )) {
1838+ $ mediaId = intval ($ property ->value );
1839+ $ widget ->assignMedia ($ mediaId );
1840+ $ newMediaIds [] = $ mediaId ;
1841+ }
17851842 }
17861843 }
1844+
1845+ $ elementTemplate ->validateProperties ('save ' );
1846+
1847+ // Convert these back into objects
1848+ // and reassert new properties.
1849+ $ elementJson [$ widgetIndex ]['elements ' ][$ elementIndex ]['properties ' ] = [];
1850+ foreach ($ elementTemplate ->getPropertyValues (
1851+ false ,
1852+ null ,
1853+ false ,
1854+ true
1855+ ) as $ propertyKey => $ propertyValue ) {
1856+ $ elementJson [$ widgetIndex ]['elements ' ][$ elementIndex ]['properties ' ][] = [
1857+ 'id ' => $ propertyKey ,
1858+ 'value ' => $ propertyValue ,
1859+ ];
1860+ }
17871861 }
17881862 }
17891863
@@ -1803,7 +1877,7 @@ public function saveElements(Request $request, Response $response, $id)
18031877 }
18041878
18051879 // Save elements
1806- $ widget ->setOptionValue ('elements ' , 'raw ' , $ elements );
1880+ $ widget ->setOptionValue ('elements ' , 'raw ' , json_encode ( $ elementJson ) );
18071881
18081882 // Unassign any mediaIds from elements which are no longer used.
18091883 foreach ($ existingMediaIds as $ existingMediaId ) {
@@ -1841,7 +1915,8 @@ public function saveElements(Request $request, Response $response, $id)
18411915 // Successful
18421916 $ this ->getState ()->hydrate ([
18431917 'httpStatus ' => 204 ,
1844- 'message ' => __ ('Saved elements ' )
1918+ 'message ' => __ ('Saved elements ' ),
1919+ 'data ' => $ elementJson ,
18451920 ]);
18461921
18471922 return $ this ->render ($ request , $ response );
0 commit comments