001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.frontoffice.search.metamodel.impl; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Objects; 024import java.util.Optional; 025import java.util.stream.Collectors; 026 027import org.ametys.cms.contenttype.MetadataType; 028import org.ametys.cms.search.query.NotQuery; 029import org.ametys.cms.search.query.OrQuery; 030import org.ametys.cms.search.query.Query; 031import org.ametys.cms.search.query.Query.Operator; 032import org.ametys.plugins.repository.AmetysObjectResolver; 033import org.ametys.plugins.repository.UnknownAmetysObjectException; 034import org.ametys.runtime.i18n.I18nizableText; 035import org.ametys.runtime.parameter.DefaultValidator; 036import org.ametys.runtime.parameter.Validator; 037import org.ametys.web.frontoffice.search.metamodel.EnumeratedValues; 038import org.ametys.web.frontoffice.search.metamodel.SearchCriterionDefinition; 039import org.ametys.web.frontoffice.search.metamodel.Searchable; 040import org.ametys.web.repository.page.Page; 041import org.ametys.web.search.query.PageQuery; 042 043/** 044 * {@link SearchCriterionDefinition} proposing a search criterion on the page of the indexed document. 045 */ 046public class PageSearchCriterionDefinition extends AbstractDefaultSearchCriterionDefinition 047{ 048 /** The ametys object resolver */ 049 private AmetysObjectResolver _resolver; 050 051 /** 052 * Default constructor 053 * @param id The id 054 * @param pluginName The plugin name 055 * @param label The label 056 * @param resolver the {@link AmetysObjectResolver} 057 * @param searchable The {@link Searchable} 058 */ 059 public PageSearchCriterionDefinition( 060 String id, 061 String pluginName, 062 I18nizableText label, 063 AmetysObjectResolver resolver, 064 Optional<Searchable> searchable) 065 { 066 super(id, pluginName, label, MetadataType.STRING, _widget(), _widgetParameters(), Optional.empty(), Optional.empty(), Optional.empty(), searchable); 067 this._resolver = resolver; 068 } 069 070 @Override 071 public boolean isEnumerated() 072 { 073 return true; 074 } 075 076 @Override 077 public boolean isTooBigForStaticEnumerator() 078 { 079 return true; 080 } 081 082 @Override 083 public Optional<EnumeratedValues> getEnumeratedValues(Map<String, Object> contextualParameters) 084 { 085 return Optional.of(new PageEnumeratedValues(this._resolver)); 086 } 087 088 private static Optional<String> _widget() 089 { 090 return Optional.of("edition.select-page"); 091 } 092 093 private static Optional<Map<String, I18nizableText>> _widgetParameters() 094 { 095 Map<String, I18nizableText> parameters = new HashMap<>(); 096 parameters.put("siteContext", new I18nizableText("all")); 097 098 return Optional.of(parameters); 099 } 100 101 @Override 102 public Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters) 103 { 104 String[] pageIds; 105 if (value instanceof String) 106 { 107 pageIds = ((String) value).split(","); 108 } 109 else if (value instanceof Collection<?>) 110 { 111 pageIds = ((Collection<?>) value) 112 .stream() 113 .filter(String.class::isInstance) 114 .map(String.class::cast) 115 .toArray(String[]::new); 116 } 117 else 118 { 119 throw new IllegalArgumentException("Not handled type of value: '" + value + "'"); 120 } 121 122 List<Query> queries = new ArrayList<>(); 123 for (String pageId : pageIds) 124 { 125 queries.add(new PageQuery(pageId, true)); 126 } 127 128 OrQuery orQuery = new OrQuery(queries); 129 return operator == Operator.NE ? new NotQuery(orQuery) : orQuery; 130 } 131 132 static class PageEnumeratedValues implements EnumeratedValues 133 { 134 /** The ametys object resolver */ 135 private AmetysObjectResolver _resolver; 136 137 public PageEnumeratedValues(AmetysObjectResolver resolver) 138 { 139 this._resolver = resolver; 140 } 141 142 public Map<Object, I18nizableText> getAllValues() 143 { 144 // Never calculate all values because too many page can be display 145 return new HashMap<>(); 146 } 147 148 public RestrictedValues getRestrictedValuesFor(List<Object> objs) 149 { 150 return new PageRestrictedValues(objs, this._resolver); 151 } 152 153 static class PageRestrictedValues implements RestrictedValues 154 { 155 private List<Object> _forObjs; 156 private AmetysObjectResolver _resolver; 157 158 PageRestrictedValues(List<Object> forObjs, AmetysObjectResolver resolver) 159 { 160 this._forObjs = forObjs; 161 this._resolver = resolver; 162 } 163 164 @Override 165 public Map<Object, I18nizableText> values() 166 { 167 return this._forObjs.stream() 168 .filter(String.class::isInstance) 169 .map(String.class::cast) 170 .map(this::_getPage) 171 .filter(Objects::nonNull) 172 .collect(Collectors.toMap(Page::getId, page -> new I18nizableText(page.getTitle()))); 173 } 174 175 private Page _getPage(String pageId) 176 { 177 try 178 { 179 return this._resolver.resolveById(pageId); 180 } 181 catch (UnknownAmetysObjectException e) 182 { 183 return null; 184 } 185 } 186 } 187 } 188 189 @Override 190 public Validator getValidator() 191 { 192 return new DefaultValidator(null, true); 193 } 194 195 public Query getEmptyValueQuery(String language, Map<String, Object> contextualParameters) 196 { 197 throw new UnsupportedOperationException("This method should not be called on the criteria PageSearchCriterionDefinition"); 198 } 199}