Someone recommended I "use code completion" and I realized that while my IDE has code completion, it doesn't recognize the large majority of methods and variables inherited from CakePHP's framework, most notably the Helper methods for views. I'm using PhpED but it seems like it's code completion is supposed to work just as it does in eclipse and other editors.
I followed this advice to no avail; I created a helpers.php file with definitions of all the helpers and included it in the project but the code completion still doesn't work with the Helpers.
I think part of the problem is Mark Story's post is from an old version of cake (I am on Cake 1.3) so I updated the definitions of the Helpers to look like this:
$this->Form = new FormHelper();
But there's still no code completion for any of the views. Is there any way to make this work? In addition to the Helpers I'd really like completion for functions like Model->find() but those don't work either.
as you might have noticed from several working code completion scripts out there you always need to put them into scope.
meaning:
you need to wrap them with the class they should be used in.
at least for components and models etc.
for helpers this is more difficult since they would be in the View scope which is not directly available/visible for IDEs in the views/layouts.
i use the app helper as scope. works for me anyway. more correct would be View class.
either way there is probably not a foolproof method for helpers. most IDE should pick it up, though.
e.g. mine (for phpdesigner):
http://www.dereuromark.de/tag/code-completion/
but the others are similar.
For PhpED you have to do the following to enable Autocompletion for $this.
Lets say you want to use $this in a Controller for something like this
$this->Project->Country->getCountryName($countryId)
First add this PhpDoc tag before the class definition
/**
* #property-read Project $Project
*/
class ProjectsController....
Now typing $this->Project should work as intended.
Next up is the Project model class.
In here add the following code, again before the class definition
/**
* #property-read Country $Country
*/
class Project extends AppModel
Now $this->Project->Country->getCountryName($countryId) works. The method is not 100% as i would like it, as PhpEDs Autocompletion sorts alphabetically, so any class starting with A or B will be shown before the methods of the Country mode.
This is not an answer to your question.
I would recommend gedit, with the word completion plugin. While not an IDE-level "Code Completion" plugin, it does an awesome job at picking up words from your source files and using those to populate its word list. It "just works" for nearly any framework, any language, because of that organic approach to building the word list. (Shameless plug to my blog, with lots of tips and tricks for how gedit can be the best editor out there: http://davidsouther.com/2011/08/gedit-tips-tricks/)
Related
I have a problem (this is not really a problem) with PhpStorm. I'm writing in pure PHP and HTML in Zend2 Views and I need to get autocomplete (Ctrl + Space) methods from all Zend ViewHelpers.
I created CustomPhpRender class that inherits from real Zend PhpRenderer.
I cannot find a solution, how can I virtually add all methods from e.g. Form ViewHelper in one line (in PHPDoc). Instead of this, of course, I can write all #method class for every method I need to get in autocomplete.
Have you got any solution how can I do it?
As far as I know, phpStorm will not auto-write the required functions for you. It will give you warnings are far as what is required. I believe it will auto-complete the function declaration for you when you go to declare a required function. It will offer a suggestion and then you hit tab. I've extended classes multiple times, and this is how it has always done it for me.
I've just started to look into MVC and I'm pretty new. I would like to port procedural code across to it but I'm struggling (please no-one suggest to use a Framework).
I can understand how it works, but understanding is different to doing. In my procedural code, I have several functions such as message(). These are called if the user does not have permission to view the current page, for example.
My problem is adding this into MVC. I've added Twig so far and I've managed to render some Twig on the index page but using functions such as message before was as easy as this:
message('Message Text');
Adding it to the controller directory would allow it to be accessed as a web page, which I don't want. And through the model, I'm not sure how to do this without requiring the file first. I could use a function, but I don't want globals and this is partly why I'm changing.
How can I properly place commonly used functions?
Edit
What I'm using is a modified version of this: http://www.phpro.org/tutorials/Model-View-Controller-MVC.html
I tend to think of traditional MVC like this:
A controller is my business logic to implement my product.
A model is the code to represent data.
A view is what represents my product.
Under this paradigm, what represents my product is what an end-user sees.
So if it's a UX component, it's part of the view.
In this way, it's pretty easy to figure out how to use it:
You could use path/to/notifications.php and then $notifications = new Notifications(); where notifications.php is a class facilitating messages like you reference.
You could extends Notifications on your view (or even a base view!) so that ANY view you instantiate immediately has access to your notifications class.
You could (though probably shouldn't) require_once( 'path/to/notifications.php' ); and then the class or functions therein would be available. Again, you probably shouldn't do it this way
The bottom line is this:
Place your old procedural code in a well organized class. It might be named something like Notifications if that's what the code does. The important thing is to organize well, name well, and do not try to force too much code into one thing.
Use that class in your code. You can explicitly use it's namespace and new an instance of it, or you can extend it to bring it along as the parent class of your view.
I have a namespace-based code, with a "Model" folder. I call my models statically everywhere in my code:
\Myapp\Model\PersonModel::doSomething()
Now, I would like to distribute my application in several countries, and be able to override some features of PersonModel for some countries (and add models for some countries, and so on).
I will have:
\MyApp\Model\France\PersonModel::doSomething()
I would like to be able to use the specialized version, with that in mind:
Not modifying too much code
Keep my IDE code completion
One solution would be to specialize every controller for every country, and use fully qualified names everywhere, but I'm not sure it is realistic (time consuming and maybe even not functional).
Another solution would be to override every model, and add a function somewhere that would give me the name of the fully qualified class (for the current country), but the code would become ugly, and I would lose code completion.
A third solution would be to have a repository for every country, and try to modify everything so that the core code is in a Git submodule and everything else is specialized classes... It seems to be the best solution to me but it seems like a Titan work, and I would prefer to have all countries inside the same repository to keep things under control.
I have really no other idea. I'm sure I'm not the only one with that problem, but I searched and found nothing. Please, tell me there is a magic feature for namespaces that I wasn't aware about, or something? :)
Edit: this is partially solved
I am now using a custom autoloader, which will load the proper country-specific class. But all country-specific classes will share the same namespace (which will work because we are using only 1 country at a given time). However, I lose code completion, but it's a tradeoff I'm ok with. If someone has a solution that would also allow to keep code completion, please feel free to answer!
Ok I found a globally satisfying solution:
All country-specific classes will share the same namespace (for example "Myapp\Model\Custom*"), which will not cause conflicts because there is only 1 country at a time.
A custom autoloader will load the proper class/file based on the current country.
Inconvenients of this solution are:
Not possible to "use" multiple countries at the same time (which is not the goal, so it's ok)
Losing code completion :(
Advantages are:
Much less time consuming and hair-pulling than creating a repo for each country
Globally clean code and code structure
Please feel free to post a more elegant solution, I will be glad to read it (and accept it)!
Another idea, following on from my thoughts in the comments. Move this:
\Myapp\Model\PersonModel
to here (random location, as I don't know your default territory):
\Myapp\Model\Germany\PersonModel
You'll now have two classes with a country in the namespace, and of course you can add more. You can now add a new generalised class, thus:
namespace \Myapp\Model;
/*
* Document your methods here using #method, so you get autocompletion
*/
class PersonModel
{
public function __callStatic($name, $args)
{
// Convert the call to an appropriate static call on the correct class.
// The first parameter is always the country name, which you can examine
// and then remove from the list. Throw an exception if $args[0] is
// empty.
}
}
You can then do this:
\MyApp\Model\PersonModel::doSomething('France', $args);
The use of #method (see here) will ensure you retain auto-completion, and you can learn more about the call magic methods here.
Of course, make sure your language-specific classes refer to a parent class, so you are not duplicating large blobs of code. Some methods may also not care about language, in which case they can go in \Myapp\Model\PersonModel, with the benefit that they do not need manual phpdoc entries.
I have a class that is based on an interface. The methods are correctly documented in the interface, however they only show up as hints if you do not document the method in the implementation class at all. (that is no docblock).
I'd like to put some form of docblock in, rather than just nothing, as it just seems a bit wrong having a method with nothing above it at all and it looks like the documentation has been forgotten. I've tried an empty block and #see, neither of which work (both break autocomplete further up the chain). Ideas?
I've been creating WordPress plug-ins for some months now and I have developed a set of "base classes" (most are abstract classes but not all of them) that I use with the plug-ins (some are used with all plug-ins, others are used when a plug-in needs the specific thing the class provides - maybe an admin screen or a button on the visual editor or whatever).
This, of course, works great BUT if I update one or more base classes to add some new functionality then if someone has more than one of my plug-ins installed it is very possible for one or more of those plug-ins to crash.
This is because if a plug-in using an older version of the updated class(es) loads earlier then it "reserves" that name and the others that require the updated class don't have the functionality/fix/etc.
I've tried "nice" solutions but the only thing I can get to work reliably is to change the actual base class names for each plug-in, which is far from ideal.
Namespaces obviously work but can't be used because so many popular hosting companies are using 5.2x versions of PHP (probably why WordPress doesn't require 5.3 either)
I tried to dynamically create the class names and to use class factories but they didn't work or didn't overcome the need to rename all the base classes. I even tried (although I didn't expect it to work but you never know with PHP):
class childClassName extends $parentClassName
This situation can't be that unusual (do people really rewrite everything from scratch everytime and/or use distinct class names) but I can't find a solution and I can't think of an elegant one. It isn't even a WordPress issue, multiple applications using common base classes within a company would have the same problem.
I also can't just force everyone to upgrade all their plug-ins every time because it may crash before they can and I'm not sure it's reasonable for me require that of them or even that I can personally update and re-test, every time, every one of the what's now almost 10 plug-ins with more in the future.
My currect best solution is to use factories to create all base classes and to put tokens in my base classes that I can do a global search and replace on so that the class names are unique for each plug-in; note the replaceable tokens alone would work.
Is there some PHP code that will allow me to achieve a simple, easy solution to this common class name conflict issue?
========================================
It doesn't look like anyone knows how to do this in PHP, maybe it can't be done, so I went with the way I mentioned above.
I thought I'd put it here because this is what I ended up with that works well, if not what I had hoped, and maybe it can help others:
I added tokens to the base class names, for example:
class someBaseClass[TokenNameGoesHere] (I used [ReplaceWithVersionNumber])
also
class someChildClass extends someBaseClass[TokenNameGoesHere]
I created a method called createNewClass and passed the class name (as a string) and any parameters to pass to the new class (in an array).
I also passed information like the token value being used in the application (version number in my case) and the namespace (to be used instead of the token value if I can use PHP 5.3 and above).
I then used reflection to create the class. While reflection is obviously slower I found that I didn't have that many times when I needed to use createNewClass so the trade off of ease of remembering and increased clarity won out.
$reflectionOfClass = new \ReflectionClass($desiredClassName);
$newObject = $reflectionOfClass->newInstanceArgs($ParametersToPass);
Where $desiredClassName is built from the class name and the other parameters: version and namespace in my case.
Then, everywhere I wanted to create a base class object I'd use:
$myNewObject = $this->createNewObject("someBaseClass", other parameters);
When I copied the class library over for a new application I just did a massive search and replace of the token with what I wanted to replace it with in all the files. It could be version number or even an empty string if I don't have to worry about clashing with other versions of my class library like I do with WordPress plug-ins.
It was pretty easy to do and works great although going back through and inserting the tokens in was tedious.
It all could, of course, be done with just tokens but I didn't want to have to remember to do put suffixes on the names and which token name I was using and whatnot.
I hope that helps someone and if anyone has a better way (which to me means less code modification and more code clarity) I'd love to hear about it.
Not sure if you've found a proper solution to your question yet. I'm dealing with the same problem and my approach (not perfect, but does what I need) would be this one:
Create a class alias of your reusable class from a variable, like this:
$aliasclass = $really_unique_prefix."_Prefix_MyPlugin_Class";
class_alias("Prefix_MyPlugin_Class", $aliasclass);
new $aliasclass();
Hope it helps!
Yes namespace is perfect solution.
If php could have provided way to unload / load classes problem could have be easily addressed. But again you need to relink / instantiate your other depended active plugins so as to used object of new classes, this involves deactivation and activation of existing plugins.
With same thought I can think of this solution, you very well know you have 1,2,3 .. n plugins using X class. 1 & 2 plugins are using older version of X and you are about to install / update plugin 3 with newer version of X. Deactivate all your plugins & first activate plugin (3) which has your latest features/version of class X, later activate all others.
$all_plugins = array(
ABSPATH.'wp-content/plugins/plugin_1/index.php',
ABSPATH.'wp-content/plugins/plugin_2/index.php'
......
ABSPATH.'wp-content/plugins/plugin_n/index.php'
);
if (class_exists('X') && X::version < currentXVersion) {
deactivate_plugins($all_plugins);
$plugin_3_lastest_class_X = ABSPATH.'wp-content/plugins/plugin_3/index.php';
array_unshift($all_plugins, $plugin_3_lastest_class_X);
activate_plugins($all_plugins);
}
*provided if its ok to deactivate / activate your plugins & you don't modify signature of existing functions of class X, you can add new functions though.