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.web.frontoffice.search.metamodel.EnumeratedValues; 036import org.ametys.web.frontoffice.search.metamodel.SearchCriterionDefinition; 037import org.ametys.web.frontoffice.search.metamodel.Searchable; 038import org.ametys.web.repository.page.Page; 039import org.ametys.web.search.query.PageQuery; 040 041/** 042 * {@link SearchCriterionDefinition} proposing a search criterion on the page of the indexed document. 043 */ 044public class PageSearchCriterionDefinition extends AbstractDefaultSearchCriterionDefinition 045{ 046 /** The ametys object resolver */ 047 private AmetysObjectResolver _resolver; 048 049 /** 050 * Default constructor 051 * @param id The id 052 * @param pluginName The plugin name 053 * @param label The label 054 * @param resolver the {@link AmetysObjectResolver} 055 * @param searchable The {@link Searchable} 056 */ 057 public PageSearchCriterionDefinition( 058 String id, 059 String pluginName, 060 I18nizableText label, 061 AmetysObjectResolver resolver, 062 Optional<Searchable> searchable) 063 { 064 super(id, pluginName, label, MetadataType.STRING, _widget(), _widgetParameters(), Optional.empty(), Optional.empty(), Optional.empty(), searchable); 065 this._resolver = resolver; 066 } 067 068 @Override 069 public boolean isEnumerated() 070 { 071 return true; 072 } 073 074 @Override 075 public boolean isTooBigForStaticEnumerator() 076 { 077 return true; 078 } 079 080 @Override 081 public Optional<EnumeratedValues> getEnumeratedValues(Map<String, Object> contextualParameters) 082 { 083 return Optional.of(new PageEnumeratedValues(this._resolver)); 084 } 085 086 private static Optional<String> _widget() 087 { 088 return Optional.of("edition.select-page"); 089 } 090 091 private static Optional<Map<String, I18nizableText>> _widgetParameters() 092 { 093 Map<String, I18nizableText> parameters = new HashMap<>(); 094 parameters.put("siteContext", new I18nizableText("all")); 095 096 return Optional.of(parameters); 097 } 098 099 @Override 100 public Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters) 101 { 102 String[] pageIds; 103 if (value instanceof String) 104 { 105 pageIds = ((String) value).split(","); 106 } 107 else if (value instanceof Collection<?>) 108 { 109 pageIds = ((Collection<?>) value) 110 .stream() 111 .filter(String.class::isInstance) 112 .map(String.class::cast) 113 .toArray(String[]::new); 114 } 115 else 116 { 117 throw new IllegalArgumentException("Not handled type of value: '" + value + "'"); 118 } 119 120 List<Query> queries = new ArrayList<>(); 121 for (String pageId : pageIds) 122 { 123 queries.add(new PageQuery(pageId, true)); 124 } 125 126 OrQuery orQuery = new OrQuery(queries); 127 return operator == Operator.NE ? new NotQuery(orQuery) : orQuery; 128 } 129 130 static class PageEnumeratedValues implements EnumeratedValues 131 { 132 /** The ametys object resolver */ 133 private AmetysObjectResolver _resolver; 134 135 public PageEnumeratedValues(AmetysObjectResolver resolver) 136 { 137 this._resolver = resolver; 138 } 139 140 public Map<Object, I18nizableText> getAllValues() 141 { 142 // Never calculate all values because too many page can be display 143 return new HashMap<>(); 144 } 145 146 public RestrictedValues getRestrictedValuesFor(List<Object> objs) 147 { 148 return new PageRestrictedValues(objs, this._resolver); 149 } 150 151 static class PageRestrictedValues implements RestrictedValues 152 { 153 private List<Object> _forObjs; 154 private AmetysObjectResolver _resolver; 155 156 PageRestrictedValues(List<Object> forObjs, AmetysObjectResolver resolver) 157 { 158 this._forObjs = forObjs; 159 this._resolver = resolver; 160 } 161 162 @Override 163 public Map<Object, I18nizableText> values() 164 { 165 return this._forObjs.stream() 166 .filter(String.class::isInstance) 167 .map(String.class::cast) 168 .map(this::_getPage) 169 .filter(Objects::nonNull) 170 .collect(Collectors.toMap(Page::getId, page -> new I18nizableText(page.getTitle()))); 171 } 172 173 private Page _getPage(String pageId) 174 { 175 try 176 { 177 return this._resolver.resolveById(pageId); 178 } 179 catch (UnknownAmetysObjectException e) 180 { 181 return null; 182 } 183 } 184 } 185 } 186}