package com.nvlad.yii2support.common; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.database.model.DasColumn; import com.intellij.database.model.DasObject; import com.intellij.database.model.DasTable; import com.intellij.database.psi.*; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment; import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocProperty; import com.jetbrains.php.lang.documentation.phpdoc.psi.tags.PhpDocPropertyTag; import com.jetbrains.php.lang.psi.elements.*; import com.jetbrains.php.lang.psi.elements.impl.ClassConstImpl; import com.jetbrains.php.lang.psi.elements.impl.StringLiteralExpressionImpl; import com.nvlad.yii2support.database.TableInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by oleg on 23.03.2017. */ public class DatabaseUtils { public static boolean HasConnections(Project project) { DbPsiFacade facade = DbPsiFacade.getInstance(project); return facade.getDataSources().size() > 0; } @Nullable public static ArrayList<LookupElementBuilder> getLookupItemsByTable(String table, Project project, PhpExpression position) { ArrayList<LookupElementBuilder> list = new ArrayList<>(); if (table == null || table.isEmpty()) return list; DbPsiFacade facade = DbPsiFacade.getInstance(project); List<DbDataSource> dataSources = facade.getDataSources(); // Code to test tests :) //dataSources.clear(); //dataSources.add(new TestDataSource(project)); for (DbDataSource source : dataSources) { for (Object item : source.getModel().traverser().children(source.getModel().getCurrentRootNamespace())) { if (item instanceof DbTable && ((DbTable) item).getName().equals(table)) { TableInfo tableInfo = new TableInfo((DbTable) item); for (DasColumn column : tableInfo.getColumns()) { list.add(DatabaseUtils.buildLookup(column, true)); } } } } return list; } public static ArrayList<LookupElementBuilder> getLookupItemsTables(Project project, PhpExpression position) { DbPsiFacade facade = DbPsiFacade.getInstance(project); List<DbDataSource> dataSources = facade.getDataSources(); // Code to test tests :) //dataSources.clear(); //dataSources.add(new TestDataSource(project)); ArrayList<LookupElementBuilder> list = new ArrayList<>(); for (DbDataSource source : dataSources) { for (Object item : source.getModel().traverser().children(source.getModel().getCurrentRootNamespace())) { if (item instanceof DbTable) { list.add(DatabaseUtils.buildLookup(item, true)); } } } return list; } public static ArrayList<LookupElementBuilder> getLookupItemsByAnnotations(PhpClass phpClass, PhpExpression position) { if (phpClass == null) return null; final ArrayList<LookupElementBuilder> result = new ArrayList<>(); final Field[] fields = phpClass.getOwnFields(); for (Field field : fields) { if (field instanceof PhpDocProperty) { result.add(buildLookup(field, false)); } } return result; } public static String[] extractParamsFromCondition(String condition) { return extractParamsFromCondition(condition, true); } public static String[] extractParamsFromCondition(String condition, boolean includeColon) { LinkedHashSet<String> matches = new LinkedHashSet<>(); String pattern = "(?<![:\\[])(:\\w+)"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(condition); while (m.find()) { String param = m.group(1); if (! includeColon) param = param.replace(":", ""); matches.add(param); } return (String[]) matches.toArray(new String[0]); } @NotNull public static LookupElementBuilder buildLookup(Object field, boolean showSchema) { String lookupString = "-"; if (field instanceof DasObject) lookupString = ((DasObject) field).getName(); if (field instanceof Field) { lookupString = ((Field) field).getName(); } LookupElementBuilder builder = LookupElementBuilder.create(field, lookupString); if (field instanceof Field) { builder = builder.withTypeText(((Field) field).getType().toString()) .withIcon(((Field) field).getIcon()); } if (field instanceof DasColumn) { DasColumn column = (DasColumn) field; builder = builder.withTypeText(column.getDataType().typeName, true); if (column.getDbParent() != null && showSchema && column.getDbParent().getDbParent() != null) { builder = builder.withTailText(" (" + column.getDbParent().getDbParent().getName() + "." + column.getDbParent().getName() + ")", true); } if (column instanceof DbColumnImpl) builder = builder.withIcon(((DbColumnImpl) column).getIcon()); } if (field instanceof DasTable) { DasTable table = (DasTable) field; DasObject tableSchema = table.getDbParent(); if (tableSchema != null) { if (tableSchema instanceof DbNamespaceImpl) builder = builder.withTypeText(((DbDataSourceImpl) ((DbNamespaceImpl) tableSchema).getParent()).getName(), true); } if (showSchema && tableSchema != null) builder = builder.withTailText(" (" + table.getDbParent().getName() + ")", true); if (table instanceof DbTableImpl) builder = builder.withIcon(((DbTableImpl) table).getIcon()); } return builder; } @Nullable public static String getTableByActiveRecordClass(PhpClass phpClass) { Method method = phpClass.findMethodByName("tableName"); if (method != null) { Collection<PhpReturn> returns = PsiTreeUtil.findChildrenOfType(method, PhpReturn.class); for (PhpReturn element : returns) { if ((element).getChildren().length > 0) { if ((element).getChildren()[0] instanceof ClassConstantReference) { PsiElement resolved = ((ClassConstantReference) (element).getChildren()[0]).resolve(); if (resolved != null && resolved instanceof ClassConstImpl) { ClassConstImpl constant = (ClassConstImpl) resolved; if (constant.getChildren().length > 0) return ((StringLiteralExpressionImpl) constant.getChildren()[0]).getContents(); } } else if ((element).getChildren()[0] instanceof StringLiteralExpression) return clearTablePrefixTags((element).getChildren()[0].getText()); } } } String className = phpClass.getName(); return StringUtils.CamelToId(className); } public static String clearTablePrefixTags(String str) { return str.replace("{{%", "").replace("}}", "").replace("{{", ""); } @Nullable public static PhpClass getClassByClassPhpDoc(PhpDocComment comment) { PsiElement nextElement = comment.getNextPsiSibling(); int limit = 10; while (limit > 0) { if (nextElement instanceof PhpClass) return (PhpClass) nextElement; else if (nextElement == null) return null; nextElement = nextElement.getNextSibling(); limit--; } return null; } @Nullable public static PhpDocComment getDocComment(PsiElement element) { PsiElement nextElement = element.getParent(); int limit = 10; while (limit > 0) { if (nextElement instanceof PhpDocComment) return (PhpDocComment) nextElement; else if (nextElement == null) return null; nextElement = nextElement.getParent(); limit--; } return null; } public static boolean isTableExists(String table, Project project) { if(table == null) return false; DbPsiFacade facade = DbPsiFacade.getInstance(project); List<DbDataSource> dataSources = facade.getDataSources(); table = ClassUtils.removeQuotes(table); for (DbDataSource source : dataSources) { for (Object item : source.getModel().traverser().children(source.getModel().getCurrentRootNamespace())) { if (item instanceof DbTable && ((DbTable) item).getName().equals(table)) { return true; } } } return false; } public static ArrayList<String> getColumnsByTable(String table, Project project) { DbPsiFacade facade = DbPsiFacade.getInstance(project); List<DbDataSource> dataSources = facade.getDataSources(); ArrayList<String> list = new ArrayList<>(); if(table == null) return list; table = ClassUtils.removeQuotes(table); for (DbDataSource source : dataSources) { for (Object item : source.getModel().traverser().children(source.getModel().getCurrentRootNamespace())) { if (item instanceof DbTable && ((DbTable) item).getName().equals(table)) { TableInfo tableInfo = new TableInfo((DbTable) item); for (DasColumn column : tableInfo.getColumns()) { list.add(ClassUtils.removeQuotes(column.getName())); } } } } return list; } public static boolean isPropertyUsed(PhpDocProperty property, ArrayList<String> columns, PhpClass phpClass) { if (property == null) return true; for (String column : columns) if (column.equals(property.getName())) return true; return ClassUtils.isFieldExists(phpClass, property.getName(), true); } public static ArrayList<PhpDocPropertyTag> getUnusedProperties(String table, List<PhpDocPropertyTag> propertyTags, PhpClass phpClass) { ArrayList<PhpDocPropertyTag> unusedProperties = new ArrayList<>(); ArrayList<String> columns = getColumnsByTable(table, phpClass.getProject()); for (PhpDocPropertyTag tag : propertyTags) { PhpDocProperty property = tag.getProperty(); if (!isPropertyUsed(property, columns, phpClass )) unusedProperties.add(tag); } return unusedProperties; } public static ArrayList<VirtualProperty> getNotDeclaredColumns(String table, Collection<Field> fields, Project project) { DbPsiFacade facade = DbPsiFacade.getInstance(project); List<DbDataSource> dataSources = facade.getDataSources(); final ArrayList<VirtualProperty> result = new ArrayList<>(); if (table == null) return result; for (DbDataSource source : dataSources) { for (Object item : source.getModel().traverser().children(source.getModel().getCurrentRootNamespace())) { table = ClassUtils.removeQuotes(table); if (item instanceof DbTable && ((DbTable) item).getName().equals(table)) { TableInfo tableInfo = new TableInfo((DbTable) item); for (DasColumn column : tableInfo.getColumns()) { boolean found = false; PhpDocProperty prevProperty = null; for (Field field : fields) { if (field != null && field.getName().equals(column.getName())) { found = true; break; } } if (!found) { VirtualProperty newItem = new VirtualProperty(column.getName(), column.getDataType().typeName, column.getDataType().toString(), column.getComment(), null); result.add(newItem); } } } } } return result; } }