├── .gitignore ├── LICENSE ├── PHPClassTemplates.iml ├── README.md ├── resources ├── META-INF │ └── plugin.xml └── fileTemplates │ └── internal │ ├── PHP Exception.php.ft │ └── PHP Exception.php.html └── src └── com └── aurimasniekis └── phpclasstemplates ├── actions ├── NewPHPExceptionClass.java └── NewPHPTemplateClass.java └── dialog ├── PhpNewClassDialog.java ├── PhpNewExceptionClassDialog.java └── PhpNewTemplateClassDialog.java /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /out 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Aurimas Niekis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PHPClassTemplates.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Class Templates 2 | 3 | [![Version](http://phpstorm.espend.de/badge/9640/version)](https://plugins.jetbrains.com/plugin/9640) 4 | [![Downloads](http://phpstorm.espend.de/badge/9640/downloads)](https://plugins.jetbrains.com/plugin/9640) 5 | [![Downloads last month](http://phpstorm.espend.de/badge/9640/last-month)](https://plugins.jetbrains.com/plugin/9640) 6 | 7 | A PHPStorm Plugin providing custom PHP class templates. 8 | 9 | * PHP Exception Class (With selection which Exception Class to extend) 10 | * PHP Class From Template (New file from `File Templates` with defined file extension `class.php` 11 | 12 | ## Install 13 | 14 | Install the plugin by going to `Settings -> Plugins -> Browse repositories` and then search for `PHP Class Templates`. 15 | 16 | ## Usage 17 | 18 | **PHP Class From Template** uses File Templates from `Settings -> Editor -> File and Code Templates -> Files` templates with file extension `class.php` 19 | 20 | **PHP Exception Class** uses File Template `PHP Exception` 21 | 22 | ## Screen Shots 23 | 24 | ![Screenshoot](http://i.imgur.com/chkN4OZ.png) 25 | ![Screenshoot](http://i.imgur.com/7CwpORb.png) 26 | ![Screenshoot](http://i.imgur.com/iaOI9J7.png) 27 | ![Screenshoot](http://i.imgur.com/lEXtmsP.png) 28 | ![Screenshoot](http://i.imgur.com/4VAKd3x.png) -------------------------------------------------------------------------------- /resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.aurimasniekis.phpclasstemplates 3 | PHP Class Templates 4 | 1.0.2 5 | Aurimas Niekis 6 | 7 | 9 | 13 | 14 |

PHP Class From Template Usage

15 | 16 |

PHP Class From Template uses File Templates with file extension "class.php"

17 | ]]> 18 |
19 | 20 | 21 | 22 | 23 | 24 | com.jetbrains.php 25 | com.intellij.modules.platform 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
-------------------------------------------------------------------------------- /resources/fileTemplates/internal/PHP Exception.php.ft: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 |
7 | This is a built-in template used each time you create a new PHP class by selecting New | PHP Class from the popup menu 8 | in one of the project views.
9 | The template is editable. Along with PHP statements, expressions and comments you can also use the predefined variables 10 | listed below. Every variable will be expanded like macros into the corresponding value.
11 | By means of the #parse directive, you can include templates from the Includes 12 | tab by specifying the full name of the desired template as a parameter in quotation marks.
13 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 60 | 61 | 62 | 63 | 64 | 67 | 68 | 69 | 70 | 71 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 84 | 85 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 |
Predefined variables will take the following values:
23 | ${FILE_NAME} 24 |  current file name
30 | ${USER} 31 |  current user system login name
37 | ${DATE} 38 |  current system date
44 | ${TIME} 45 |  current system time
51 | ${YEAR} 52 |  current year
58 | ${MONTH} 59 |  current month
65 | ${DAY} 66 |  current day of the month
72 | ${HOUR} 73 |  current hour
79 | ${MINUTE} 80 |  current minute
86 | ${PRODUCT_NAME} 87 |  current IDE name
93 | ${PROJECT_NAME} 94 |  current project name
100 | ${DS} 101 |  Dollar sign, evaluates to a plain '$' character.
106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/com/aurimasniekis/phpclasstemplates/actions/NewPHPExceptionClass.java: -------------------------------------------------------------------------------- 1 | package com.aurimasniekis.phpclasstemplates.actions; 2 | 3 | import com.aurimasniekis.phpclasstemplates.dialog.PhpNewExceptionClassDialog; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.psi.PsiDirectory; 6 | import com.intellij.psi.PsiFile; 7 | import com.jetbrains.php.actions.PhpNewBaseAction; 8 | import com.jetbrains.php.actions.PhpNewClassDialog; 9 | import com.jetbrains.php.templates.PhpCreateFileFromTemplateDataProvider; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public class NewPHPExceptionClass extends PhpNewBaseAction { 14 | public NewPHPExceptionClass() 15 | { 16 | super("PHP Exception Class", "Creates new PHP exception class"); 17 | } 18 | 19 | protected PhpCreateFileFromTemplateDataProvider getDataProvider(@NotNull Project project, @NotNull PsiDirectory dir, @Nullable PsiFile file) { 20 | PhpNewExceptionClassDialog dialog = new PhpNewExceptionClassDialog(project, dir); 21 | 22 | if (!dialog.showAndGet()) { 23 | return null; 24 | } 25 | 26 | return dialog; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/aurimasniekis/phpclasstemplates/actions/NewPHPTemplateClass.java: -------------------------------------------------------------------------------- 1 | package com.aurimasniekis.phpclasstemplates.actions; 2 | 3 | import com.aurimasniekis.phpclasstemplates.dialog.PhpNewExceptionClassDialog; 4 | import com.aurimasniekis.phpclasstemplates.dialog.PhpNewTemplateClassDialog; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiDirectory; 7 | import com.intellij.psi.PsiFile; 8 | import com.jetbrains.php.actions.PhpNewBaseAction; 9 | import com.jetbrains.php.templates.PhpCreateFileFromTemplateDataProvider; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.jetbrains.annotations.Nullable; 12 | 13 | public class NewPHPTemplateClass extends PhpNewBaseAction { 14 | public NewPHPTemplateClass() 15 | { 16 | super("PHP Class From Template", "Creates new PHP Class from template"); 17 | } 18 | 19 | protected PhpCreateFileFromTemplateDataProvider getDataProvider(@NotNull Project project, @NotNull PsiDirectory dir, @Nullable PsiFile file) { 20 | PhpNewTemplateClassDialog dialog = new PhpNewTemplateClassDialog(project, dir); 21 | 22 | if (!dialog.showAndGet()) { 23 | return null; 24 | } 25 | 26 | return dialog; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/aurimasniekis/phpclasstemplates/dialog/PhpNewClassDialog.java: -------------------------------------------------------------------------------- 1 | package com.aurimasniekis.phpclasstemplates.dialog; 2 | 3 | import com.intellij.openapi.Disposable; 4 | import com.intellij.openapi.actionSystem.AnAction; 5 | import com.intellij.openapi.actionSystem.CustomShortcutSet; 6 | import com.intellij.openapi.actionSystem.KeyboardShortcut; 7 | import com.intellij.openapi.actionSystem.Shortcut; 8 | import com.intellij.openapi.editor.event.DocumentAdapter; 9 | import com.intellij.openapi.editor.event.DocumentEvent; 10 | import com.intellij.openapi.editor.event.DocumentListener; 11 | import com.intellij.openapi.project.Project; 12 | import com.intellij.openapi.ui.ComboBox; 13 | import com.intellij.openapi.ui.DialogWrapper; 14 | import com.intellij.openapi.ui.ValidationInfo; 15 | import com.intellij.openapi.util.Disposer; 16 | import com.intellij.openapi.util.text.StringUtil; 17 | import com.intellij.openapi.vfs.VirtualFile; 18 | import com.intellij.psi.PsiDirectory; 19 | import com.intellij.psi.PsiManager; 20 | import com.intellij.ui.EditorTextField; 21 | import com.intellij.util.Alarm; 22 | import com.intellij.util.ArrayUtil; 23 | import com.intellij.util.PathUtil; 24 | import com.intellij.util.PlatformIcons; 25 | import com.intellij.util.ui.FormBuilder; 26 | import com.jetbrains.php.PhpBundle; 27 | import com.jetbrains.php.actions.PhpNewFileDialog; 28 | import com.jetbrains.php.lang.PhpLangUtil; 29 | import com.jetbrains.php.refactoring.PhpNameUtil; 30 | import com.jetbrains.php.roots.PhpDirectoryByPsrProvider; 31 | import com.jetbrains.php.roots.PhpNamespaceCompositeProvider; 32 | import com.jetbrains.php.roots.ui.PhpNamespaceComboBox; 33 | import com.jetbrains.php.roots.ui.PhpPsrDirectoryComboBox; 34 | import com.jetbrains.php.templates.PhpCreateFileFromTemplateDataProvider; 35 | import com.jetbrains.php.templates.PhpFileTemplateUtil; 36 | import com.jetbrains.php.templates.PhpTemplatesSettings; 37 | import com.jetbrains.php.ui.PhpUiUtil; 38 | import org.jetbrains.annotations.NotNull; 39 | import org.jetbrains.annotations.Nullable; 40 | 41 | import javax.swing.*; 42 | import java.awt.*; 43 | import java.awt.event.FocusAdapter; 44 | import java.awt.event.FocusEvent; 45 | import java.io.File; 46 | import java.util.List; 47 | import java.util.Properties; 48 | 49 | abstract public class PhpNewClassDialog extends DialogWrapper implements PhpCreateFileFromTemplateDataProvider { 50 | protected FormBuilder myBuilder; 51 | 52 | protected Project myProject; 53 | protected PsiDirectory myDirectory; 54 | protected DocumentListener myNameFieldListener; 55 | protected final Alarm myAlarm; 56 | protected boolean myDisposed; 57 | 58 | protected EditorTextField myNameTextField; 59 | protected PhpNamespaceComboBox myNamespaceCombobox; 60 | protected PhpPsrDirectoryComboBox myDirectoryCombobox; 61 | protected EditorTextField myFileNameTextField; 62 | protected ComboBox myExtensionComboBox; 63 | protected Properties myProperties; 64 | 65 | protected JLabel myExtensionUpDownHint; 66 | 67 | public PhpNewClassDialog(@NotNull Project project, @Nullable PsiDirectory directory) { 68 | super(project); 69 | 70 | this.myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); 71 | 72 | Disposer.register(this.getDisposable(), new Disposable() { 73 | public void dispose() { 74 | PhpNewClassDialog.this.myAlarm.cancelAllRequests(); 75 | PhpNewClassDialog.this.myDisposed = true; 76 | } 77 | }); 78 | 79 | this.myProperties = new Properties(); 80 | 81 | this.myProject = project; 82 | this.myDirectory = directory; 83 | 84 | init(); 85 | } 86 | 87 | protected void initMainFields() { 88 | // Setup Name Field 89 | this.myNameTextField = new EditorTextField(); 90 | this.myNameTextField.setCaretPosition(0); 91 | 92 | // Setup Namespace Combobox 93 | this.myNamespaceCombobox = new PhpNamespaceComboBox( 94 | this.myProject, 95 | "", 96 | this.getDisposable() 97 | ); 98 | 99 | this.myNamespaceCombobox.setEditable(true); 100 | this.myNamespaceCombobox.setMinimumAndPreferredWidth(400); 101 | 102 | this.myFileNameTextField = new EditorTextField(); 103 | 104 | this.myDirectoryCombobox = new PhpPsrDirectoryComboBox(this.myProject) { 105 | public List suggestDirectories(@NotNull String namespace) { 106 | return PhpDirectoryByPsrProvider.getSourceRootProvide().suggestDirectories( 107 | PhpNewClassDialog.this.myProject, 108 | namespace, 109 | this.myBaseDir, 110 | this.myBaseNamespace 111 | ); 112 | } 113 | }; 114 | 115 | 116 | if(this.myDirectory != null) { 117 | List namespaces = PhpNamespaceCompositeProvider.INSTANCE.suggestNamespaces(this.myDirectory); 118 | 119 | String mainSuggestion = ""; 120 | if (namespaces != null && !namespaces.isEmpty()) { 121 | mainSuggestion = (String)namespaces.get(0); 122 | } 123 | 124 | List suggestions = null; 125 | if (namespaces != null && namespaces.size() > 1) { 126 | suggestions = namespaces.subList(1, namespaces.size()); 127 | } 128 | 129 | this.myNamespaceCombobox.updateItems(mainSuggestion, suggestions); 130 | this.myDirectoryCombobox.init( 131 | this.myDirectory.getVirtualFile(), 132 | this.getNamespace() 133 | ); 134 | } else { 135 | this.myDirectoryCombobox.init( 136 | this.myProject.getBaseDir(), 137 | "" 138 | ); 139 | } 140 | 141 | this.myDirectoryCombobox.getComboBox().addFocusListener( 142 | new FocusAdapter() { 143 | public void focusGained(FocusEvent e) { 144 | PhpNewClassDialog.this.myDirectoryCombobox.getComboBox().setEditable(true); 145 | } 146 | } 147 | ); 148 | 149 | // File Extension Combobox 150 | this.myExtensionComboBox = new ComboBox(); 151 | this.myExtensionComboBox.setMinimumAndPreferredWidth(400); 152 | 153 | String[] registeredExtensions = PhpFileTemplateUtil.getRegisteredPhpFileExtensions(); 154 | this.myExtensionComboBox.setModel(new DefaultComboBoxModel(registeredExtensions)); 155 | int indexOfLast = ArrayUtil.indexOf( 156 | registeredExtensions, 157 | PhpTemplatesSettings.getInstance(this.myProject).NEW_PHP_CLASS_LAST_EXTENSION 158 | ); 159 | 160 | if(indexOfLast > -1) { 161 | this.myExtensionComboBox.setSelectedIndex(indexOfLast); 162 | } else { 163 | this.myExtensionComboBox.setSelectedIndex(0); 164 | } 165 | 166 | 167 | this.myExtensionUpDownHint = new JLabel(); 168 | this.myExtensionUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS); 169 | this.myExtensionUpDownHint.setToolTipText(PhpBundle.message("actions.new.php.base.arrows.extension.tooltip")); 170 | 171 | 172 | if(this.isFileNameAutoUpdate()) { 173 | this.myNameFieldListener = new DocumentAdapter() { 174 | public void documentChanged(DocumentEvent e) { 175 | PhpNewClassDialog.this.addUpdateRequest(() -> { 176 | PhpNewClassDialog.this.myFileNameTextField.setText(PhpNewClassDialog.this.getName()); 177 | }, 10); 178 | } 179 | }; 180 | this.myNameTextField.getDocument().addDocumentListener(this.myNameFieldListener); 181 | this.myNamespaceCombobox.getEditorTextField().addDocumentListener(new DocumentAdapter() { 182 | public void documentChanged(DocumentEvent event) { 183 | PhpNewClassDialog.this.addUpdateRequest(() -> { 184 | PhpNewClassDialog.this.myDirectoryCombobox.updateDirectories(PhpNewClassDialog.this.getNamespace()); 185 | }, 10); 186 | } 187 | }); 188 | } 189 | 190 | AnAction extensionArrow = PhpNewFileDialog.getCbArrowAction(this.myExtensionComboBox); 191 | KeyboardShortcut up = new KeyboardShortcut(KeyStroke.getKeyStroke(38, 0), (KeyStroke)null); 192 | KeyboardShortcut down = new KeyboardShortcut(KeyStroke.getKeyStroke(40, 0), (KeyStroke)null); 193 | extensionArrow.registerCustomShortcutSet(new CustomShortcutSet(new Shortcut[]{up, down}), this.myFileNameTextField); 194 | } 195 | 196 | protected void subInit() { 197 | this.myBuilder = new FormBuilder(); 198 | this.myBuilder.setVerticalGap(5); 199 | this.initMainFields(); 200 | } 201 | 202 | @Override 203 | protected void init() { 204 | this.subInit(); 205 | 206 | this.buildForm(); 207 | 208 | super.init(); 209 | } 210 | 211 | protected void buildForm() { 212 | BorderLayout layout = new BorderLayout(); 213 | layout.setHgap(5); 214 | JPanel filenamePanel = new JPanel(layout); 215 | filenamePanel.add(this.myFileNameTextField, BorderLayout.CENTER); 216 | filenamePanel.add(this.myExtensionUpDownHint, BorderLayout.EAST); 217 | 218 | 219 | this.myBuilder.addLabeledComponent(new JLabel("Namespace:"), this.myNamespaceCombobox); 220 | this.myBuilder.addTooltip( 221 | PhpBundle.message( 222 | "0.completion.shortcut", 223 | "namespace", PhpUiUtil.getShortcutTextByActionName("CodeCompletion")) 224 | ); 225 | this.myBuilder.addLabeledComponent(new JLabel("Filename:"), filenamePanel); 226 | this.myBuilder.addLabeledComponent(new JLabel("Directory:"), this.myDirectoryCombobox); 227 | this.myBuilder.addTooltip( 228 | PhpBundle.message( 229 | "0.completion.shortcut", 230 | "path", PhpUiUtil.getShortcutTextByActionName("CodeCompletion")) 231 | ); 232 | this.myBuilder.addLabeledComponent(new JLabel("File Extension:"), this.myExtensionComboBox); 233 | } 234 | 235 | @Nullable 236 | @Override 237 | public JComponent getPreferredFocusedComponent() { 238 | return this.myNameTextField; 239 | } 240 | 241 | @Override 242 | protected JComponent createCenterPanel() { 243 | return this.myBuilder.getPanel(); 244 | } 245 | 246 | @NotNull 247 | public String getFileName() { 248 | return this.getFileNameText().trim(); 249 | } 250 | 251 | public String getFileNameText() { 252 | return this.myFileNameTextField.getText(); 253 | } 254 | 255 | @NotNull 256 | protected String getName() { 257 | return this.myNameTextField.getText().trim(); 258 | } 259 | 260 | protected void doOKAction() { 261 | PhpTemplatesSettings.getInstance(this.myProject).NEW_PHP_CLASS_LAST_EXTENSION = this.getExtension(); 262 | super.doOKAction(); 263 | } 264 | 265 | @NotNull 266 | public String getTemplateName() { 267 | return "PHP Class"; 268 | } 269 | 270 | @NotNull 271 | protected String getExtension() { 272 | return (String)this.myExtensionComboBox.getSelectedItem(); 273 | } 274 | 275 | @NotNull 276 | @Override 277 | public PsiDirectory getBaseDirectory() { 278 | return this.myDirectory; 279 | } 280 | 281 | public String getClassName() { 282 | return this.myNameTextField.getText(); 283 | } 284 | 285 | public String getNamespaceName() { 286 | return this.getNamespace(); 287 | } 288 | 289 | @NotNull 290 | protected final String getNamespace() { 291 | return PhpLangUtil.toName(this.myNamespaceCombobox.getSelectedNamespace().trim()); 292 | } 293 | 294 | protected boolean isFileNameAutoUpdate() { 295 | return true; 296 | } 297 | 298 | protected void addUpdateRequest(@NotNull Runnable runnable) { 299 | this.addUpdateRequest(runnable, 100); 300 | } 301 | 302 | protected void addUpdateRequest(@NotNull Runnable runnable, int delay) { 303 | SwingUtilities.invokeLater(() -> { 304 | if(!this.myDisposed) { 305 | this.myAlarm.cancelAllRequests(); 306 | this.myAlarm.addRequest(runnable, delay); 307 | } 308 | }); 309 | } 310 | 311 | protected void dispose() { 312 | if(this.isFileNameAutoUpdate()) { 313 | this.myNameTextField.getDocument().removeDocumentListener(this.myNameFieldListener); 314 | } 315 | 316 | super.dispose(); 317 | } 318 | 319 | @NotNull 320 | public final String getFilePath() { 321 | String chosenExtension = this.getExtension(); 322 | String filename = PathUtil.toSystemIndependentName(this.getFileName()); 323 | String extension = PhpNameUtil.getExtension(filename); 324 | String fullFileName = chosenExtension.equals(extension)?filename:PhpNameUtil.getFullFileName(filename, chosenExtension); 325 | String relativePath = this.myDirectoryCombobox.getRelativePath(); 326 | return StringUtil.isEmpty(relativePath)?fullFileName:relativePath + "/" + StringUtil.trimEnd(fullFileName, "/"); 327 | } 328 | 329 | @Nullable 330 | protected PsiDirectory getDirectory() { 331 | VirtualFile directory = this.myDirectoryCombobox.getExistingParent(); 332 | if(directory != null) { 333 | PsiDirectory psiDirectory = PsiManager.getInstance(this.myProject).findDirectory(directory); 334 | if(psiDirectory != null) { 335 | return psiDirectory; 336 | } 337 | } 338 | 339 | return null; 340 | } 341 | 342 | @NotNull 343 | public Properties getProperties(@NotNull PsiDirectory directory) { 344 | 345 | this.myProperties.setProperty("NAME", this.getName()); 346 | String namespace = this.getNamespace(); 347 | if(StringUtil.isNotEmpty(namespace)) { 348 | this.myProperties.setProperty("NAMESPACE", namespace); 349 | } 350 | 351 | return this.myProperties; 352 | } 353 | 354 | protected boolean postponeValidation() { 355 | return true; 356 | } 357 | 358 | protected ValidationInfo doValidate() { 359 | String name = this.getName(); 360 | if(!PhpNameUtil.isValidClassName(name)) { 361 | return new ValidationInfo( 362 | PhpBundle.message( 363 | "validation.class.not.valid.name", 364 | name), 365 | this.myNameTextField 366 | ); 367 | } else { 368 | String namespace = this.getNamespace(); 369 | if(StringUtil.isNotEmpty(namespace) && !PhpNameUtil.isValidNamespaceFullName(namespace)) { 370 | return new ValidationInfo( 371 | PhpBundle.message( 372 | "validation.namespace.not.valid.name", 373 | namespace), 374 | this.myNamespaceCombobox 375 | ); 376 | } else { 377 | PsiDirectory directory = this.getDirectory(); 378 | if(directory == null) { 379 | return new ValidationInfo( 380 | PhpBundle.message( 381 | "validation.value.is.not.specified.or.invalid", 382 | "directory") 383 | ); 384 | } else { 385 | String errorMessage = this.isValidFilePath(this.getFilePath(), directory); 386 | return errorMessage != null?new ValidationInfo(errorMessage, this.myFileNameTextField):null; 387 | } 388 | } 389 | } 390 | } 391 | 392 | protected String isValidFilePath(@NotNull String fullFilePath, @NotNull PsiDirectory baseDirectory) { 393 | String filePath = StringUtil.replace( 394 | fullFilePath, 395 | File.separator, 396 | "/" 397 | ); 398 | 399 | if(filePath.length() == 0) { 400 | return PhpBundle.message( 401 | "validation.file.not.valid.name", 402 | fullFilePath); 403 | } else { 404 | List split = StringUtil.split(filePath, "/"); 405 | if(split.size() == 0) { 406 | return PhpBundle.message( 407 | "validation.file.not.valid.name", 408 | fullFilePath); 409 | } else { 410 | for (String aSplit : split) { 411 | if (!PhpNameUtil.isValidFileName(aSplit)) { 412 | return PhpBundle.message( 413 | "validation.file.not.valid.name", 414 | fullFilePath); 415 | } 416 | } 417 | 418 | VirtualFile baseDirectoryFile = baseDirectory.getVirtualFile(); 419 | VirtualFile fileByRelativePath = baseDirectoryFile.findFileByRelativePath( 420 | PhpNameUtil.trimStart( 421 | filePath, 422 | '/') 423 | ); 424 | 425 | if (fileByRelativePath != null) { 426 | return PhpBundle.message( 427 | "validation.file.already.exists", 428 | fullFilePath); 429 | } else { 430 | return null; 431 | } 432 | } 433 | } 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /src/com/aurimasniekis/phpclasstemplates/dialog/PhpNewExceptionClassDialog.java: -------------------------------------------------------------------------------- 1 | package com.aurimasniekis.phpclasstemplates.dialog; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.CustomShortcutSet; 5 | import com.intellij.openapi.actionSystem.KeyboardShortcut; 6 | import com.intellij.openapi.actionSystem.Shortcut; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.openapi.ui.ComboBox; 9 | import com.intellij.openapi.util.Trinity; 10 | import com.intellij.openapi.util.text.StringUtil; 11 | import com.intellij.psi.PsiDirectory; 12 | import com.intellij.ui.ComboboxSpeedSearch; 13 | import com.intellij.ui.EditorTextField; 14 | import com.intellij.ui.ListCellRendererWrapper; 15 | import com.intellij.util.PlatformIcons; 16 | import com.jetbrains.php.PhpBundle; 17 | import com.jetbrains.php.PhpIcons; 18 | import com.jetbrains.php.actions.PhpNewFileDialog; 19 | import org.jetbrains.annotations.NotNull; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | import javax.swing.*; 23 | import java.awt.*; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.Properties; 27 | 28 | public class PhpNewExceptionClassDialog extends PhpNewClassDialog { 29 | protected EditorTextField myMessageTextField; 30 | protected ComboBox myKindComboBox; 31 | protected JLabel myKindUpDownHint; 32 | 33 | public PhpNewExceptionClassDialog(@NotNull Project project, @Nullable PsiDirectory directory) { 34 | super(project, directory); 35 | } 36 | 37 | @Override 38 | protected void subInit() { 39 | super.subInit(); 40 | 41 | this.myMessageTextField = new EditorTextField(""); 42 | this.myKindUpDownHint = new JLabel(); 43 | this.myKindUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS); 44 | this.myKindUpDownHint.setToolTipText(PhpBundle.message("actions.new.php.base.arrows.kind.tooltip")); 45 | 46 | 47 | this.myKindComboBox = new ComboBox(); 48 | this.myKindComboBox.setMinimumAndPreferredWidth(400); 49 | this.myKindComboBox.setRenderer(new ListCellRendererWrapper() { 50 | public void customize(JList list, Trinity value, int index, boolean selected, boolean hasFocus) { 51 | this.setText((String)value.first); 52 | this.setIcon((Icon)value.second); 53 | } 54 | }); 55 | ComboboxSpeedSearch var10001 = new ComboboxSpeedSearch(this.myKindComboBox) { 56 | protected String getElementText(Object element) { 57 | return (String)((Trinity)element).first; 58 | } 59 | }; 60 | KeyboardShortcut up = new KeyboardShortcut(KeyStroke.getKeyStroke(38, 0), (KeyStroke)null); 61 | KeyboardShortcut down = new KeyboardShortcut(KeyStroke.getKeyStroke(40, 0), (KeyStroke)null); 62 | AnAction kindArrow = PhpNewFileDialog.getCbArrowAction(this.myKindComboBox); 63 | kindArrow.registerCustomShortcutSet(new CustomShortcutSet(new Shortcut[]{up, down}), this.myNameTextField); 64 | List exceptionTypes = this.getExceptionTypes(); 65 | 66 | for(Trinity type : exceptionTypes) { 67 | this.myKindComboBox.addItem(type); 68 | } 69 | } 70 | 71 | @Override 72 | protected void buildForm() { 73 | this.setTitle("Create New PHP Exception Class"); 74 | this.myNameTextField.setText("Exception"); 75 | this.myFileNameTextField.setText("Exception"); 76 | BorderLayout layout = new BorderLayout(); 77 | layout.setHgap(5); 78 | JPanel namePanel = new JPanel(layout); 79 | namePanel.add(this.myNameTextField, BorderLayout.CENTER); 80 | namePanel.add(this.myKindUpDownHint, BorderLayout.EAST); 81 | 82 | this.myBuilder.addLabeledComponent(new JLabel("Name:"), namePanel); 83 | this.myBuilder.addLabeledComponent(new JLabel("Type:"), this.myKindComboBox); 84 | this.myBuilder.addTooltip("Exeception class to extend"); 85 | this.myBuilder.addLabeledComponent(new JLabel("Message:"), this.myMessageTextField); 86 | this.myBuilder.addTooltip("Enter message to create constructor with specified message"); 87 | 88 | 89 | super.buildForm(); 90 | } 91 | 92 | private List getExceptionTypes() { 93 | List types = new ArrayList(); 94 | 95 | types.add(new Trinity("Exception", PhpIcons.EXCEPTION, "PHP Exception")); 96 | types.add(new Trinity("Error", PhpIcons.EXCEPTION, "PHP Exception")); 97 | types.add(new Trinity("BadFunctionCallException", PhpIcons.EXCEPTION, "PHP Exception")); 98 | types.add(new Trinity("BadMethodCallException", PhpIcons.EXCEPTION, "PHP Exception")); 99 | types.add(new Trinity("DomainException", PhpIcons.EXCEPTION, "PHP Exception")); 100 | types.add(new Trinity("InvalidArgumentException", PhpIcons.EXCEPTION, "PHP Exception")); 101 | types.add(new Trinity("LengthException", PhpIcons.EXCEPTION, "PHP Exception")); 102 | types.add(new Trinity("LogicException", PhpIcons.EXCEPTION, "PHP Exception")); 103 | types.add(new Trinity("OutOfBoundsException", PhpIcons.EXCEPTION, "PHP Exception")); 104 | types.add(new Trinity("OutOfRangeException", PhpIcons.EXCEPTION, "PHP Exception")); 105 | types.add(new Trinity("OverflowException", PhpIcons.EXCEPTION, "PHP Exception")); 106 | types.add(new Trinity("RangeException", PhpIcons.EXCEPTION, "PHP Exception")); 107 | types.add(new Trinity("RuntimeException", PhpIcons.EXCEPTION, "PHP Exception")); 108 | types.add(new Trinity("UnderflowException", PhpIcons.EXCEPTION, "PHP Exception")); 109 | types.add(new Trinity("UnexpectedValueException", PhpIcons.EXCEPTION, "PHP Exception")); 110 | 111 | return types; 112 | } 113 | 114 | @NotNull 115 | public Properties getProperties(@NotNull PsiDirectory directory) { 116 | super.getProperties(directory); 117 | 118 | this.myProperties.setProperty("EXCEPTION", (String)((Trinity)this.myKindComboBox.getSelectedItem()).getFirst()); 119 | String exceptionMessage = this.myMessageTextField.getText(); 120 | 121 | if (StringUtil.isNotEmpty(exceptionMessage)) { 122 | this.myProperties.setProperty("EXCEPTION_MESSAGE", exceptionMessage); 123 | } 124 | 125 | return this.myProperties; 126 | } 127 | 128 | @NotNull 129 | public String getTemplateName() { 130 | return (String)((Trinity)this.myKindComboBox.getSelectedItem()).getThird(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/com/aurimasniekis/phpclasstemplates/dialog/PhpNewTemplateClassDialog.java: -------------------------------------------------------------------------------- 1 | package com.aurimasniekis.phpclasstemplates.dialog; 2 | 3 | import com.intellij.ide.fileTemplates.FileTemplate; 4 | import com.intellij.ide.fileTemplates.FileTemplateManager; 5 | import com.intellij.openapi.actionSystem.AnAction; 6 | import com.intellij.openapi.actionSystem.CustomShortcutSet; 7 | import com.intellij.openapi.actionSystem.KeyboardShortcut; 8 | import com.intellij.openapi.actionSystem.Shortcut; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.ui.ComboBox; 11 | import com.intellij.openapi.util.Trinity; 12 | import com.intellij.openapi.util.text.StringUtil; 13 | import com.intellij.psi.PsiDirectory; 14 | import com.intellij.ui.ComboboxSpeedSearch; 15 | import com.intellij.ui.EditorTextField; 16 | import com.intellij.ui.ListCellRendererWrapper; 17 | import com.intellij.util.PlatformIcons; 18 | import com.intellij.util.ui.FormBuilder; 19 | import com.jetbrains.php.PhpBundle; 20 | import com.jetbrains.php.PhpIcons; 21 | import com.jetbrains.php.actions.PhpNewFileDialog; 22 | import org.apache.velocity.runtime.parser.ParseException; 23 | import org.jetbrains.annotations.NotNull; 24 | import org.jetbrains.annotations.Nullable; 25 | import sun.jvm.hotspot.ui.Editor; 26 | import sun.jvm.hotspot.utilities.HashtableEntry; 27 | 28 | import javax.swing.*; 29 | import java.awt.*; 30 | import java.util.*; 31 | import java.util.List; 32 | 33 | public class PhpNewTemplateClassDialog extends PhpNewClassDialog { 34 | protected EditorTextField myMessageTextField; 35 | protected ComboBox myKindComboBox; 36 | protected JLabel myKindUpDownHint; 37 | protected FormBuilder myTemplateAttributes; 38 | protected FileTemplate myCurrentTemplate; 39 | protected Hashtable myTemplateAttributesFields; 40 | 41 | public PhpNewTemplateClassDialog(@NotNull Project project, @Nullable PsiDirectory directory) { 42 | super(project, directory); 43 | } 44 | 45 | @Override 46 | protected void subInit() { 47 | super.subInit(); 48 | 49 | this.myTemplateAttributes = new FormBuilder(); 50 | this.myTemplateAttributesFields = new Hashtable(); 51 | 52 | this.myKindUpDownHint = new JLabel(); 53 | this.myKindUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS); 54 | this.myKindUpDownHint.setToolTipText("Pressing Up or Down arrows while in editor changes the template"); 55 | 56 | 57 | this.myKindComboBox = new ComboBox(); 58 | this.myKindComboBox.setMinimumAndPreferredWidth(400); 59 | this.myKindComboBox.setRenderer(new ListCellRendererWrapper() { 60 | public void customize(JList list, Trinity value, int index, boolean selected, boolean hasFocus) { 61 | this.setText((String) value.first); 62 | this.setIcon((Icon) value.second); 63 | } 64 | }); 65 | ComboboxSpeedSearch var10001 = new ComboboxSpeedSearch(this.myKindComboBox) { 66 | protected String getElementText(Object element) { 67 | return (String) ((Trinity) element).first; 68 | } 69 | }; 70 | KeyboardShortcut up = new KeyboardShortcut(KeyStroke.getKeyStroke(38, 0), (KeyStroke) null); 71 | KeyboardShortcut down = new KeyboardShortcut(KeyStroke.getKeyStroke(40, 0), (KeyStroke) null); 72 | AnAction kindArrow = PhpNewFileDialog.getCbArrowAction(this.myKindComboBox); 73 | kindArrow.registerCustomShortcutSet(new CustomShortcutSet(new Shortcut[]{up, down}), this.myNameTextField); 74 | List availableTemplates = this.getAvailableTemplates(); 75 | 76 | for (Trinity type : availableTemplates) { 77 | this.myKindComboBox.addItem(type); 78 | } 79 | 80 | this.myKindComboBox.addActionListener(e -> { 81 | this.updateTemplateAttributes(); 82 | }); 83 | 84 | this.updateTemplateAttributes(); 85 | } 86 | 87 | private void updateTemplateAttributes() { 88 | FileTemplate template = (FileTemplate) ((Trinity) this.myKindComboBox.getSelectedItem()).getThird(); 89 | 90 | if (template.equals(this.myCurrentTemplate)) { 91 | return; 92 | } 93 | 94 | this.myCurrentTemplate = template; 95 | this.myTemplateAttributes.getPanel().removeAll(); 96 | this.myTemplateAttributesFields.clear(); 97 | 98 | String[] attrs = new String[0]; 99 | try { 100 | attrs = template.getUnsetAttributes(this.getProperties(this.getDirectory()), this.myProject); 101 | } catch (ParseException e1) { 102 | e1.printStackTrace(); 103 | } 104 | 105 | List ignoredAttributes = Arrays.asList("PROJECT_NAME", "FILE_NAME", "NAME", "USER", "DATE", "TIME", "YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "PRODUCT_NAME", "MONTH_NAME_SHORT", "MONTH_NAME_FULL", "NAME", "NAMESPACE", "CLASS_NAME", "STATIC", "TYPE_HINT", "PARAM_DOC", "THROWS_DOC", "DS", "CARET"); 106 | for (String attribute : attrs) { 107 | 108 | if (ignoredAttributes.contains(attribute)) { 109 | continue; 110 | } 111 | 112 | EditorTextField field = new EditorTextField(); 113 | 114 | this.myTemplateAttributesFields.put(attribute, field); 115 | this.myTemplateAttributes.addLabeledComponent(attribute.concat(":"), field); 116 | } 117 | 118 | this.myTemplateAttributes.getPanel().revalidate(); 119 | this.myTemplateAttributes.getPanel().repaint(); 120 | } 121 | 122 | @Override 123 | protected void buildForm() { 124 | this.setTitle("Create New PHP Class From Template"); 125 | BorderLayout layout = new BorderLayout(); 126 | layout.setHgap(5); 127 | JPanel namePanel = new JPanel(layout); 128 | namePanel.add(this.myNameTextField, BorderLayout.CENTER); 129 | namePanel.add(this.myKindUpDownHint, BorderLayout.EAST); 130 | 131 | this.myBuilder.addLabeledComponent(new JLabel("Name:"), namePanel); 132 | this.myBuilder.addLabeledComponent(new JLabel("Template:"), this.myKindComboBox); 133 | this.myBuilder.addComponent(this.myTemplateAttributes.getPanel()); 134 | 135 | super.buildForm(); 136 | } 137 | 138 | private List getAvailableTemplates() { 139 | List templates = new ArrayList(); 140 | 141 | FileTemplate classTemplate = FileTemplateManager.getInstance(this.myProject).getInternalTemplate("PHP Class"); 142 | 143 | for (FileTemplate template : FileTemplateManager.getInstance(this.myProject).getAllTemplates()) { 144 | if (template.getExtension().equals("class.php")) { 145 | templates.add(new Trinity(template.getName(), PhpIcons.CLASS, template)); 146 | } 147 | } 148 | 149 | if (templates.size() < 1) { 150 | templates.add(new Trinity(classTemplate.getName(), PhpIcons.CLASS, classTemplate)); 151 | } 152 | 153 | return templates; 154 | } 155 | 156 | @NotNull 157 | public Properties getProperties(@NotNull PsiDirectory directory) { 158 | super.getProperties(directory); 159 | 160 | return this.myProperties; 161 | } 162 | 163 | @Override 164 | protected void doOKAction() { 165 | Iterator> it = this.myTemplateAttributesFields.entrySet().iterator(); 166 | 167 | while (it.hasNext()) { 168 | Map.Entry entry = it.next(); 169 | 170 | this.myProperties.setProperty(entry.getKey(), entry.getValue().getText()); 171 | } 172 | 173 | super.doOKAction(); 174 | } 175 | 176 | @NotNull 177 | public String getTemplateName() { 178 | return (String) ((Trinity) this.myKindComboBox.getSelectedItem()).getFirst(); 179 | } 180 | 181 | @NotNull 182 | public String getFileTemplate() { 183 | return (String) ((Trinity) this.myKindComboBox.getSelectedItem()).getThird(); 184 | } 185 | } 186 | --------------------------------------------------------------------------------