/******************************************************************************* * Copyright (c) 2017 Rogue Wave Software Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Rogue Wave Software Inc. - initial implementation *******************************************************************************/ package org.eclipse.php.internal.ui.wizards.types; import java.util.List; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.declarations.MethodDeclaration; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.references.SimpleReference; import org.eclipse.dltk.core.*; import org.eclipse.php.core.compiler.ast.nodes.*; import org.eclipse.php.internal.core.typeinference.PHPModelUtils; import org.eclipse.php.internal.ui.Logger; import org.eclipse.php.internal.ui.PHPUiPlugin; /** * This class represents the template for creating a PHP class code. * */ public class PHPClassTemplate extends PHPElementTemplate { private String requiredPHPsBlock; public PHPClassTemplate() { super(); } @Override public String getTemplatePath() { return TypeWizardConstants.CLASS_TEMPLATE_LOCATION; } @Override public String processTemplate(NewPHPElementData data) { // handle class default PHPDOC set(DEFAULT_PHPDOC_VAR, ""); //$NON-NLS-1$ // handle superclass declaration extract(INPUT, SUPERCLASS_STRUCT, SUPERCLASS_STRUCT_COMPILED); set(SUPERCLASS_STRUCT, ""); //$NON-NLS-1$ if (data.superClass != null) { String superClass = data.superClass.getElementName(); if (!isImported(data, data.superClass)) { superClass = "\\" + superClass; //$NON-NLS-1$ } set(SUPERCLASS_NAME_VAR, superClass); compile(SUPERCLASS_STRUCT_COMPILED, SUPERCLASS_STRUCT, true); } // handle interfaces declaration extract(INPUT, INTERFACES_STRUCT, INTERFACES_STRUCT_COMPILED); set(INTERFACES_STRUCT, ""); //$NON-NLS-1$ if (data.interfaces.length > 0) { for (int i = 0; i < data.interfaces.length; i++) { String interfaceName = data.interfaces[i].getElementName(); if (!isImported(data, data.interfaces[i])) { interfaceName = "\\" + interfaceName; //$NON-NLS-1$ } // if not the last interface name, add the ',' if ((i + 1) < data.interfaces.length) { interfaceName += ", "; //$NON-NLS-1$ } set(INTERFACE_NAME_VAR, interfaceName); compile(INTERFACES_STRUCT_COMPILED, INTERFACES_STRUCT, true); } } extract(INPUT, IMPLEMENTS_STRUCT, IMPLEMENTS_STRUCT_COMPILED); set(IMPLEMENTS_STRUCT, ""); //$NON-NLS-1$ if (data.interfaces.length > 0) { compile(IMPLEMENTS_STRUCT_COMPILED, IMPLEMENTS_STRUCT, true); } // handle traits declaration extract(INPUT, TRAITS_STRUCT, TRAITS_STRUCT_COMPILED); set(TRAITS_STRUCT, ""); //$NON-NLS-1$ if (data.traits.length > 0) { for (int i = 0; i < data.traits.length; i++) { String interfaceName = data.traits[i].getElementName(); if (!isImported(data, data.traits[i])) { interfaceName = "\\" + interfaceName; //$NON-NLS-1$ } // if not the last interface name, add the ',' if ((i + 1) < data.traits.length) { interfaceName += ", "; //$NON-NLS-1$ } set(TRAIT_NAME_VAR, interfaceName); compile(TRAITS_STRUCT_COMPILED, TRAITS_STRUCT, true); } } extract(INPUT, USESTRAITS_STRUCT, USESTRAITS_STRUCT_COMPILED); set(USESTRAITS_STRUCT, ""); //$NON-NLS-1$ if (data.traits.length > 0) { compile(USESTRAITS_STRUCT_COMPILED, USESTRAITS_STRUCT, true); } // handle methods content extract(INPUT, FUNC_PARAMS_STRUCT, FUNC_PARAMS_STRUCT_COMPILED);// extract // method // params extract(INPUT, FUNC_PHPDOC_PARAMS_STRUCT, FUNC_PHPDOC_PARAMS_STRUCT_COMPILED);// extract // method // phpdoc // params extract(INPUT, FUNC_PHPDOC_STRUCT, FUNC_PHPDOC_STRUCT_COMPILED);// extract // method // phpdoc extract(INPUT, FUNCTIONS_STRUCT, FUNCTIONS_STRUCT_COMPILED);// extract // method set(FUNC_PARAMS_STRUCT, ""); //$NON-NLS-1$ set(FUNC_PHPDOC_STRUCT, ""); //$NON-NLS-1$ set(FUNCTIONS_STRUCT, ""); //$NON-NLS-1$ set(FUNCTION_MODIFIER_VAR, ""); //$NON-NLS-1$ set(FUNCTION_STATIC_VAR, ""); //$NON-NLS-1$ set(FUNCTION_PARENT_CALL, ""); //$NON-NLS-1$ // handle constructor if (data.isGenerateConstructor && !containsFunction(data.funcsToAdd, TypeWizardConstants.PHP5_CONSTRUCTOR_TEMPLATE)) { generateConstructor(data); } // generate methods ! set(TODO_VAR, ""); //$NON-NLS-1$ if (data.funcsToAdd.length > 0) { generateInheritedMethods(data, data.funcsToAdd); set(TODO_VAR, ""); //$NON-NLS-1$ } else { // fixed bug 14453 - change the class template and add todo // comment for the class in case of no methods. if (data.isGenerateTODOs) { set(TODO_VAR, TODO_TEXT); } } // handle destructor if (data.isGenerateDestructor && !containsFunction(data.funcsToAdd, TypeWizardConstants.PHP5_DESTRUCTOR_TEMPLATE)) { generateDestructor(data); } // handle class extract(INPUT, CLASS_STRUCT, CLASS_STRUCT_COMPILED); set(CLASS_STRUCT, ""); //$NON-NLS-1$ set(ABSTRACT_VAR, ""); //$NON-NLS-1$ set(FINAL_VAR, ""); //$NON-NLS-1$ if (data.isFinal) { set(FINAL_VAR, FINAL_TEXT); } if (data.isAbstract) { set(ABSTRACT_VAR, ABSTRACT_TEXT); } // Generate the PHPDoc for class. if (data.isGeneratePHPDoc) { set(DEFAULT_PHPDOC_VAR, getDefaultPHPDoc()); } set(CLASS_NAME_VAR, data.className); set(ELEMENT_TYPE_VAR, TypeWizardConstants.CLASS_TYPE); compile(CLASS_STRUCT_COMPILED, CLASS_STRUCT, false); // handle namespace extract(INPUT, NAMESPACE_STRUCT, NAMESPACE_STRUCT_COMPILED); set(NAMESPACE_STRUCT, ""); //$NON-NLS-1$ if (data.namespace != null && !data.namespace.isEmpty()) { set(NAMESPACE_NAME, data.namespace); compile(NAMESPACE_STRUCT_COMPILED, NAMESPACE_STRUCT, true); } // handle requires list declaration handleRequires(data); // handle use extract(INPUT, USE_STRUCT, USE_STRUCT_COMPILED); set(USE_STRUCT, ""); //$NON-NLS-1$ for (int i = 0; i < data.imports.length; i++) { set(USE, data.imports[i]); compile(USE_STRUCT_COMPILED, USE_STRUCT, true); } // handle namespace in existing file extract(CLASS_STRUCT, NAMESPACE_IN_FILE_STRUCT, NAMESPACE_IN_FILE_STRUCT_COMPILED); set(NAMESPACE_IN_FILE_STRUCT, ""); //$NON-NLS-1$ // handle use in existing file extract(CLASS_STRUCT, USE_IN_FILE_STRUCT, USE_IN_STRUCT_COMPILED); set(USE_IN_FILE_STRUCT, ""); //$NON-NLS-1$ if (data.isExistingFile && data.isInFirstBlock) { if (data.namespace != null && !data.namespace.isEmpty()) { set(NAMESPACE_NAME, data.namespace); compile(NAMESPACE_IN_FILE_STRUCT_COMPILED, NAMESPACE_IN_FILE_STRUCT, true); } for (int i = 0; i < data.imports.length; i++) { set(USE, data.imports[i]); compile(USE_IN_STRUCT_COMPILED, USE_IN_FILE_STRUCT, true); } } // handle php_content extract(INPUT, PHP_CONTENT_STRUCT, PHP_CONTENT_STRUCT_COMPILED); compile(PHP_CONTENT_STRUCT_COMPILED, PHP_CONTENT_STRUCT, false); // a new php file or a new block ==> include the PHP open/close tag in // string if (!data.isExistingFile || (data.isExistingFile && !data.isInFirstBlock) || (data.isExistingFile && data.isInFirstBlock && !data.hasFirstBlock)) { compile(get(PHP_CONTENT_STRUCT)); return compile(get(INPUT)); } // an existing file, take only class code else { return compile(get(CLASS_STRUCT)); } } private void generateInheritedMethods(NewPHPElementData data, IMethod[] methodsToOverride) { MethodDeclaration decl = null; ISourceModule sourceModule = null; for (int i = 0; i < methodsToOverride.length; i++) { IMethod func = methodsToOverride[i]; sourceModule = func.getSourceModule(); ModuleDeclaration module = SourceParserUtil.getModuleDeclaration(sourceModule); try { decl = PHPModelUtils.getNodeByMethod(module, func); } catch (ModelException e) { PHPUiPlugin.log(e); return; } // check for PHPDoc if (data.isGeneratePHPDoc) { set(FUNC_PHPDOC_PARAM_VAR, "(non-PHPdoc)"); //$NON-NLS-1$ String targetTypeName = func.getDeclaringType() .getTypeQualifiedName(PHPModelUtils.ENCLOSING_TYPE_SEPARATOR); if (targetTypeName.indexOf(PHPModelUtils.ENCLOSING_TYPE_SEPARATOR) > 0) { targetTypeName = PHPModelUtils.ENCLOSING_TYPE_SEPARATOR + targetTypeName; } set(FUNC_PHPDOC_SEE_VAR, "* @see " + targetTypeName + "::" //$NON-NLS-1$ //$NON-NLS-2$ + func.getElementName() + "()\n"); //$NON-NLS-1$ compile(FUNC_PHPDOC_PARAMS_STRUCT_COMPILED, FUNC_PHPDOC_PARAMS_STRUCT, false); compile(FUNC_PHPDOC_STRUCT_COMPILED, FUNC_PHPDOC_STRUCT, false); } // loop on all function's params List<?> paramsList = decl.getArguments(); FormalParameter[] params = paramsList.toArray(new FormalParameter[paramsList.size()]); set(FUNC_PARAM_NAME_VAR, ""); //$NON-NLS-1$ compile(FUNC_PARAMS_STRUCT_COMPILED, FUNC_PARAMS_STRUCT, false); for (int k = 0; k < params.length; k++) { SimpleReference referenceType = null; if (params[k].getParameterType() != null) { referenceType = params[k].getParameterType(); } String argType = null; if (referenceType != null) { argType = referenceType.getName(); boolean isExcluded = false;// check if the param's type // should be added to the method // arguments for (String comparedType : EXCLUDE_PARAM_TYPES_LIST) { if (comparedType.equalsIgnoreCase(argType)) { isExcluded = true; break; } } if (isExcluded) { argType = ""; //$NON-NLS-1$ } else { argType += " "; //$NON-NLS-1$ } } else { argType = ""; //$NON-NLS-1$ } String funcParam = argType + params[k].getName(); // handle default value ASTNode node = params[k].getInitialization(); String sourceCode = null; try { String defaultValue = null; if (node != null) { sourceCode = sourceModule.getSource(); if (sourceCode != null) { defaultValue = sourceCode.substring(node.sourceStart(), node.sourceEnd()); } } if (defaultValue != null && !defaultValue.equals("")) { //$NON-NLS-1$ funcParam += " = " + defaultValue; //$NON-NLS-1$ } if ((k + 1) < params.length) { funcParam += ","; //$NON-NLS-1$ } set(FUNC_PARAM_NAME_VAR, funcParam); compile(FUNC_PARAMS_STRUCT_COMPILED, FUNC_PARAMS_STRUCT, true); } catch (ModelException e) { Logger.logException(e); } } if (data.isGenerateTODOs) { set(TODO_VAR, TODO_TEXT); } else { set(TODO_VAR, ""); //$NON-NLS-1$ } set(FUNCTION_PARENT_CALL, ""); //$NON-NLS-1$ int flags = 0; try { flags = func.getFlags(); } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } String funcModifier = getVisibilityModifier(flags); set(FUNCTION_MODIFIER_VAR, funcModifier); if (isStaticFunction(func.getElementType())) { set(FUNCTION_STATIC_VAR, TypeWizardConstants.STATIC_MODIFIER); } else { set(FUNCTION_STATIC_VAR, ""); //$NON-NLS-1$ } set(FUNCTION_NAME_VAR, func.getElementName()); compile(FUNCTIONS_STRUCT_COMPILED, FUNCTIONS_STRUCT, true); } } // generates a constructor private void generateConstructor(NewPHPElementData data) { IMethod func = null; if (data.superClass != null) { IMethod[] methods = null; try { methods = data.superClass.getMethods(); } catch (ModelException e) { Logger.logException(e); } if (methods != null) { for (IMethod m : methods) { String elName = m.getElementName(); if (elName.equalsIgnoreCase(data.superClass.getElementName()) || elName.equalsIgnoreCase("__construct")) { //$NON-NLS-1$ func = m; break; } } } } MethodDeclaration decl = null; if (func != null) { ISourceModule sourceModule = func.getSourceModule(); ModuleDeclaration module = SourceParserUtil.getModuleDeclaration(sourceModule); try { decl = PHPModelUtils.getNodeByMethod(module, func); } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } // check for PHPDoc if (data.isGeneratePHPDoc) { set(FUNC_PHPDOC_PARAM_VAR, ""); //$NON-NLS-1$ set(FUNC_PHPDOC_SEE_VAR, ""); //$NON-NLS-1$ compile(FUNC_PHPDOC_PARAMS_STRUCT_COMPILED, FUNC_PHPDOC_PARAMS_STRUCT, false); if (func != null) { PHPDocBlock docBlock = null; if (decl != null && decl instanceof IPHPDocAwareDeclaration) { IPHPDocAwareDeclaration docDecl = (IPHPDocAwareDeclaration) decl; docBlock = docDecl.getPHPDoc(); } if (docBlock != null) { PHPDocTag[] tags = docBlock.getTags(); // loop on all phpdoc params for (PHPDocTag docTag : tags) { String phpdocParamType = " " //$NON-NLS-1$ + docTag.getTagKind().getValue(); String phpdocParamValue = docTag.getValue(); set(FUNC_PHPDOC_PARAM_VAR, phpdocParamType + " " + phpdocParamValue); //$NON-NLS-1$ compile(FUNC_PHPDOC_PARAMS_STRUCT_COMPILED, FUNC_PHPDOC_PARAMS_STRUCT, true); } } else { if (decl != null) { List<?> paramsList = decl.getArguments(); FormalParameter[] params = paramsList.toArray(new FormalParameter[paramsList.size()]); if (params != null) { for (int k = 0; k < params.length; k++) { String funcParam = params[k].getName(); if (params[k].getParameterType() != null) { funcParam = params[k].getParameterType().getName() + " " + funcParam; //$NON-NLS-1$ } set(FUNC_PHPDOC_PARAM_VAR, " @param " //$NON-NLS-1$ + funcParam + "\n"); //$NON-NLS-1$ compile(FUNC_PHPDOC_PARAMS_STRUCT_COMPILED, FUNC_PHPDOC_PARAMS_STRUCT, true); } } } } } compile(FUNC_PHPDOC_STRUCT_COMPILED, FUNC_PHPDOC_STRUCT, false); } // loop on all function's params FormalParameter[] params = null; if (decl != null) { List<?> paramsList = decl.getArguments(); params = paramsList.toArray(new FormalParameter[paramsList.size()]); } StringBuilder paramsOverriden = new StringBuilder(); if (func != null) { paramsOverriden.append("parent::__construct("); //$NON-NLS-1$ } set(FUNC_PARAM_NAME_VAR, ""); //$NON-NLS-1$ compile(FUNC_PARAMS_STRUCT_COMPILED, FUNC_PARAMS_STRUCT, false); String defaultValue = null; if (params != null) { for (int k = 0; k < params.length; k++) { String funcParam = params[k].getName(); // handle default value ASTNode argumentDefaultValueNode = params[k].getInitialization(); if (argumentDefaultValueNode instanceof Scalar) { Scalar scalarNode = (Scalar) argumentDefaultValueNode; defaultValue = scalarNode.getValue(); } if (defaultValue != null && !defaultValue.equals("")) { //$NON-NLS-1$ funcParam += " = " + defaultValue; //$NON-NLS-1$ } if ((k + 1) < params.length) { funcParam += ","; //$NON-NLS-1$ } paramsOverriden.append(funcParam); if (params[k].getParameterType() != null) { funcParam = params[k].getParameterType().getName() + " " //$NON-NLS-1$ + funcParam; } set(FUNC_PARAM_NAME_VAR, funcParam); compile(FUNC_PARAMS_STRUCT_COMPILED, FUNC_PARAMS_STRUCT, true); } } if (func != null) { paramsOverriden.append(");"); //$NON-NLS-1$ } set(FUNCTION_PARENT_CALL, paramsOverriden.toString()); if (data.isGenerateTODOs) { set(TODO_VAR, TODO_TEXT); } else { set(TODO_VAR, ""); //$NON-NLS-1$ } String funcModifier = "public"; //$NON-NLS-1$ String funcName = TypeWizardConstants.PHP5_CONSTRUCTOR_TEMPLATE; if (func != null) { int flags = 0; try { flags = func.getFlags(); } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } funcModifier = getVisibilityModifier(flags); funcName = func.getElementName(); } set(FUNCTION_MODIFIER_VAR, funcModifier); set(FUNCTION_NAME_VAR, funcName); compile(FUNCTIONS_STRUCT_COMPILED, FUNCTIONS_STRUCT, true); } // generates a destructor private void generateDestructor(NewPHPElementData data) { set(FUNCTION_PARENT_CALL, ""); //$NON-NLS-1$ if (data.isGeneratePHPDoc) { set(FUNC_PHPDOC_PARAM_VAR, ""); //$NON-NLS-1$ set(FUNC_PHPDOC_SEE_VAR, ""); //$NON-NLS-1$ compile(FUNC_PHPDOC_PARAMS_STRUCT_COMPILED, FUNC_PHPDOC_PARAMS_STRUCT, false); compile(FUNC_PHPDOC_STRUCT_COMPILED, FUNC_PHPDOC_STRUCT, false); } set(FUNC_PARAM_NAME_VAR, ""); //$NON-NLS-1$ compile(FUNC_PARAMS_STRUCT_COMPILED, FUNC_PARAMS_STRUCT, false); // fixed bug 14452 - empty the TODO_VAR in case of isGenerateTODOs is // false if (data.isGenerateTODOs) { set(TODO_VAR, TODO_TEXT); } else { set(TODO_VAR, ""); //$NON-NLS-1$ } set(FUNCTION_MODIFIER_VAR, ""); //$NON-NLS-1$ set(FUNCTION_NAME_VAR, TypeWizardConstants.PHP5_DESTRUCTOR_TEMPLATE); compile(FUNCTIONS_STRUCT_COMPILED, FUNCTIONS_STRUCT, true); } @Override public String getRequiredPHPs() { return requiredPHPsBlock; } /** * returns true if the given functions array contains a function by the * given name This method is used for avoiding multiple declaration of * constructors and destructors. * * @param funcs * the functions array to search in * @param name * the name of the function to look for * @return true if there is a function by the name "name" in the array * "funcs" */ private boolean containsFunction(IMethod[] funcs, String name) { for (int i = 0; i < funcs.length; i++) { if (funcs[i].getElementName().equalsIgnoreCase(name)) { return true; } } return false; } }