Skip to content

Commit

Permalink
#28896 Create Factory method to find categories in all levels (#29021)
Browse files Browse the repository at this point in the history
This is the first PR for #28896

Later I am going to use this Factory to create a API Method

### Proposed Changes
* Create Method to find categories in all levels and apply a filter


https://github.com/dotCMS/core/pull/29021/files#diff-bf828c747c99cefe73af7cec527db7f7e64bd4a66ba54a55eb1170f6a2996333R844

* Update the Cache with the result


https://github.com/dotCMS/core/pull/29021/files#diff-bf828c747c99cefe73af7cec527db7f7e64bd4a66ba54a55eb1170f6a2996333R863

We already have a method to find the ALL the categories and it update
the cache after execute the query, so I created a Util method to share
the code.


https://github.com/dotCMS/core/pull/29021/files#diff-bf828c747c99cefe73af7cec527db7f7e64bd4a66ba54a55eb1170f6a2996333R168

### Checklist
- [ ] Tests
- [ ] Translations
- [ ] Security Implications Contemplated (add notes if applicable)

### Additional Info
** any additional useful context or info **

### Screenshots
Original             |  Updated
:-------------------------:|:-------------------------:
** original screenshot **  |  ** updated screenshot **
  • Loading branch information
freddyDOTCMS authored Jul 1, 2024
1 parent c7243f5 commit 7e09771
Show file tree
Hide file tree
Showing 3 changed files with 462 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package com.dotmarketing.portlets.categories.business;

import java.util.Collection;
import java.util.List;

import com.dotcms.util.PaginationUtil;
import com.dotcms.util.pagination.OrderDirection;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.portlets.categories.model.Category;
import com.liferay.portal.model.User;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.QueryParam;

/**
*
Expand Down Expand Up @@ -273,5 +280,68 @@ public abstract class CategoryFactory {
* @throws DotDataException
*/
abstract protected List<Category> getAllChildren(Categorizable parent) throws DotDataException;

/**
* Return a {@link Category} Collection looking through the entire category tree starting from a specified inode.
* This means the search will begin from the specified inode category and then proceed recursively through its children.
*
* @param searchCriteria Search Criteria
*
* @return List of Category filtered
*/
public abstract Collection<Category> findAll(final CategorySearchCriteria searchCriteria) throws DotDataException;

/**
* Represents Search Criteria for {@link Category} searching, you cans set the follow:
*
* - filter: Value used to filter the Category by, returning only Categories that contain this value in their key, name, or variable name.
* - inode: Entry point on the Category tree to start the searching.
* - orderBy: Field name to order the Category
* - direction: Order by direction, it can be 'ASC' or 'DESC'
*/
public static class CategorySearchCriteria {
final String rootInode;
final String filter;
final String orderBy;
final OrderDirection direction;

private CategorySearchCriteria (final Builder builder) {
this.rootInode = builder.rootInode;
this.filter = builder.filter;
this.orderBy = builder.orderBy;
this.direction = builder.direction;
}

public static class Builder {
private String rootInode;
private String filter;
private String orderBy = "category_name";
private OrderDirection direction = OrderDirection.ASC;

public Builder rootInode(String rootInode) {
this.rootInode = rootInode;
return this;
}

public Builder filter(String filter) {
this.filter = filter;
return this;
}

public Builder orderBy(String orderBy) {
this.orderBy = orderBy;
return this;
}

public Builder direction(OrderDirection direction) {
this.direction = direction;
return this;
}

public CategorySearchCriteria build() {
return new CategorySearchCriteria(this);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,16 @@
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.dotmarketing.util.VelocityUtil;
import com.liferay.util.StringPool;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
*
Expand Down Expand Up @@ -165,15 +164,7 @@ protected List<Category> findAll() throws DotDataException {
.loadObjectResults();

List<Category> categories = convertForCategories(result);
for(final Category category : categories) {
//Updating the cache since we are already loading all the categories
if(catCache.get(category.getInode()) == null)
try {
catCache.put(category);
} catch (DotCacheException e) {
throw new DotDataException(e.getMessage(), e);
}
}
updateCache(categories);
return categories;
}

Expand Down Expand Up @@ -843,4 +834,72 @@ protected String suggestVelocityVarName(final String categoryVelVarName) throws
throw new DotDataException("Unable to suggest a variable name. Got to:" + var);
}

/**
* Default Implementation for {@link CategoryFactory#findAll(CategorySearchCriteria)}
* @param searchCriteria Search Criteria
*
* @return
* @throws DotDataException
*/
public List<Category> findAll(final CategorySearchCriteria searchCriteria)
throws DotDataException {

if (!UtilMethods.isSet(searchCriteria.rootInode) && !UtilMethods.isSet(searchCriteria.filter)) {
return findAll();
}

final String query = getFindAllSQLQuery(searchCriteria);

final DotConnect dc = new DotConnect().setSQL(query);

if (UtilMethods.isSet(searchCriteria.rootInode) ) {
dc.addObject(searchCriteria.rootInode);
}

if (UtilMethods.isSet(searchCriteria.filter) ) {
dc.addObject("%" + searchCriteria.filter.toLowerCase() + "%");
dc.addObject("%" + searchCriteria.filter.toLowerCase() + "%");
dc.addObject("%" + searchCriteria.filter.toLowerCase() + "%");
}

final List<Category> categories = convertForCategories(UtilMethods.isSet(searchCriteria.rootInode) ?
dc.loadObjectResults().stream()
.filter(map -> !map.get("inode").equals(searchCriteria.rootInode))
.collect(Collectors.toList()) : dc.loadObjectResults());

updateCache(categories);
return categories;
}

private static String getFindAllSQLQuery(CategorySearchCriteria searchCriteria) {
final String queryTemplate = "WITH RECURSIVE CategoryHierarchy AS ( " +
"SELECT c.* FROM Category c %s " +
"UNION ALL " +
"SELECT c.* FROM Category c JOIN tree t ON c.inode = t.child JOIN CategoryHierarchy ch ON t.parent = ch.inode " +
") " +
"SELECT * FROM CategoryHierarchy %s ORDER BY %s %s";

final String rootCategoryFilter = UtilMethods.isSet(searchCriteria.rootInode) ? "WHERE c.inode = ?" : StringPool.BLANK;

final String filterCategories = UtilMethods.isSet(searchCriteria.filter) ?
"WHERE LOWER(category_name) LIKE ? OR " +
"LOWER(category_key) LIKE ? OR " +
"LOWER(category_velocity_var_name) LIKE ?" : StringPool.BLANK;

final String query = String.format(queryTemplate, rootCategoryFilter, filterCategories, searchCriteria.orderBy,
searchCriteria.direction.toString());
return query;
}

private void updateCache(List<Category> categories) throws DotDataException {
for(final Category category : categories) {
if(catCache.get(category.getInode()) == null)
try {
catCache.put(category);
} catch (DotCacheException e) {
throw new DotDataException(e.getMessage(), e);
}
}
}

}
Loading

0 comments on commit 7e09771

Please sign in to comment.