When creating form elements with Zend (using Zend Studio for Eclipse), I'd like some auto completion or hints. Here's what I'm thinking. I'm sure these exist, but I don't know how to get them.
I type createElement and auto-completes gives me the signature createElement($type, $name). Great, I select it.
but when I try to set the $type I don't get any hints like DateTextBox or ValidationTextBox. Being new, I see how this can be useful. What do you do to remember all the options?
for the array of attributes like require, invalidMessage, I'd like to get a list of those to choose from, and/or auto-complete when I start typing one.
// Date field
$date = $this->createElement('DateTextBox', 'date',
array('require' => 'true', 'invalidMessage' => 'Invalid date format')
);
$date->setLabel('date')->setRequired(true);
You have few options to help yourself, without waiting for any plugin:
learn it and remember ;)
extend your phpDoc blocks with all available options:
Example (to be honest I don't know if Eclipse supports html in phpDoc or even any text after variable name in #param, but it works fine in Netbeans):
/**
* [...]
* #param string $type Can be: <ul><li>DateTextBox</li><li>ValidationTextBox</li></ul>
* #param string $name Whatever
* #param array|Zend_Config $options Array with following keys: <ul><li>require</li><li>invalidMessage</li></ul>
* #return Zend_Form_Element
*/
public function createElement($type, $name, $options = null)
extend Zend class and create your own methods to simplify your work
Example:
class My_Zend_Form_Element extends Zend_Form_Element
{
public function createDateTextBox($name, $options = null)
{
return $this->createElement('DateTextBox', $name, $options);
}
}
declare some well named constants and provide some hint in phpDoc
Example: (type ZFE_OPTIONS and IDE should show hint with some constants to use as array keys)
/**
* Can be true or false
*/
define('ZFE_OPTIONS_REQUIRE','require');
create your own helper classes with methods to produce valid options array
Example:
class ZFE_Options
{
protected $opts = array();
/**
* #param bool $req
* #return ZFE_Options
*/
public function setRequired($req){
$this->opts['require'] = (bool)$req;
return $this;
}
/**
* #param string $txt
* #return ZFE_Options
*/
public function setInvalidMessage($txt){
$this->opts['invalidMessage'] = (string)$txt;
return $this;
}
/**
* #return array
*/
public function toArray(){
return $this->opts;
}
}
$zfe_options = new ZFE_Options();
$opts = $zfe_options
->setRequired(true)
->setInvalidMessage('Please provide valid email address')
->toArray();
That's not possible. It's not how autocompletion works. The hints you get are taken directly from ZF's code documentation. Nothing more, nothing less. Everything you see as hints is taken directly from the DocBlock and method signature, e.g.
/**
* Create an element
*
* Acts as a factory for creating elements. Elements created with this
* method will not be attached to the form, but will contain element
* settings as specified in the form object (including plugin loader
* prefix paths, default decorators, etc.).
*
* #param string $type
* #param string $name
* #param array|Zend_Config $options
* #return Zend_Form_Element
*/
public function createElement($type, $name, $options = null)
Eclipse can tell you to insert a string or an array and it will know that the method returns a Zend_Form_Element, but it cannot tell you what these strings should be.
The only place where I know something like what you describe exists is for CSS files. For some reason, when I type in display: it will give me an autocomplete box with possible values for this declaration. If you want more sophisticated autocomplete like this, consider filing this as a feature request to Zend.
Related
I can not figure out how to deserialize a object from a array of IDs? Here is a simple example my array.
"roles":["1","2","3"]
But when trying I get the error that object expected-class AppBundle\Entity\Role... is There something for this? Thank you all for your attention!
The problem is the one mentioned by LBA in his answer. Basically in order for jms serializer to create an object, it need to be provided with an Array. The solution if you are ok with changing the structure of the api is also good.
I'm assuming your $role jms configuration looks something like this
/**
* #var ArrayCollection
*
* #JMS\Expose
* #JMS\Accessor(setter="setRoles")
* #JMS\SerializedName("roles")
* #JMS\Type("ArrayCollection<Role>")
* #JMS\Groups({"...."})
*
*/
private $roles;
In this case Jms will expect to get and array of arrays just like LBA mentioned. If instead you want he keep the current structure ("roles":["1","2","3"]) instead of "roles":["id": 1], ["id": 2], ["id": 3]], there is an alternative. You can extend the JsonDeserializationVisitor and this a very powerful tool in your arsenal to do almost anything you like with jms.
To do this first change your #Type like this(you will understand why latter)
* #JMS\Type("ArrayCollection<Role,Expand<id>>")
Now you use parameter overwrite, to extend JsonDeserializationVisitor, like this
<parameter key="jms_serializer.json_deserialization_visitor.class">MyBundle\Services\JsonDeserializationVisitor.php</parameter>
And then go and define the new Visitor something like this.
<?php
namespace MyBundle\Services\JmsSerializer;
use JMS\Serializer\Context;
use JMS\Serializer\JsonDeserializationVisitor as ParentJsonDeserializationVisitor;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
class JsonDeserializationVisitor extends ParentJsonDeserializationVisitor
{
/**
* #param PropertyMetadata $metadata
* #param mixed $data
* #param Context $context
*/
public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
{
//This type is the information you put into the #Type annotation.
$type = $metadata->type;
$expand = null;
.......
/*Here you can extract the Expand<id> part that you added to the #Type config.
The Expand part will help you identify the fact that this property needs to be expanded and the id part will tell you how to expand id.
Based on if you do find this you will probably set a variable like $expand = $key, where $key is the "id" part.*/
......
if ($expand !== null) {
$expandedData = [];
foreach($data as $key->$value)
{
$expandedData[$key]=["$expand":$value];
}
parent::visitProperty($metadata, $expandedData, $context);
} else {
parent::visitProperty($metadata, $data, $context);
}
}
This is the basic stuff. Feel free to refactor the code however you like, this is just for fast proof of concept. Also Expand is just how i named this into the exemple. You can use it with whatever name you like. Sorry for not providing the code to extract this from $type but i don't remember the structure of $type right now. Also the structure will change if you do something like Expand<'id'> so play with it and see which fits best for you. Basically with this method you can extend and add features to any jms type you want. For instance you can add something like
#JMS\Type("string<translatable>")
And then extend JsonSerializationVisitor:visitString to call $translator->trans($data) on $data before returning it, and so you can translate a string before serializing it.
Something like this
<?php
namespace MyBundle\Service\JmsSerializer;
use JMS\Serializer\Context;
use JMS\Serializer\JsonSerializationVisitor as ParentJsonSerializationVisitor;
use Symfony\Component\Translation\Translator;
class JsonSerializationVisitor extends ParentJsonSerializationVisitor
{
/**
* #var Translator;
*/
private $translator;
const TRANSLATABLE = "translatable";
/**
* #param string $data
* #param array $type
* #param Context $context
* #return string
*/
public function visitString($data, array $type, Context $context)
{
$translatable = $this->getParameters(self::TRANSLATABLE, $type['params']);
if ($translatable) {
$data = (string)$this->translator->trans($data);
}
return parent::visitString($data, $type, $context);
}
.....................
Hope this helps. Let me know if you have any questions.
Alexandru Cosoi
It is deserializing your array, but it tries to deserialize it into an array of objects of type AppBundle\Entity\Role which seems not to be compatible with your values "1", "2" and so on and therefore throws an error as it cannot instansiate the objects.
You'll have to make sure that your content fits to the expected class.
If you can share your Class Definition for Role we might be able to help you how your array should look like (e.g. something like [["id": 1], ["id": 2], ["id": 3]] probably).
Is it possible in PHPStorm to type hint an array with different object types, ie:
public function getThings()
{
return array (new Thing(), new OtherThing(), new SomethingElse());
}
Even declaring them separately before building the array doesn't seem to work.
you can use phpdocs in order for phpstorm to accept an array of multiple types like so:
/**
* #return Thing[] | OtherThing[] | SomethingElse[]
*
*/
public function getThings()
{
return array (new Thing(), new OtherThing(), new SomethingElse());
}
This technique will make phpstorm think that the array could contain any of those objects and so it will give you type hinting for all three.
Alternatively you can make all of the objects extend another object or implement an interface and type hint that once object or interface like so:
/**
* #return ExtensionClass[]
*
*/
public function getThings()
{
return array (new Thing(), new OtherThing(), new SomethingElse());
}
This will give you type hints for only what the classes extend or implement from the parent class or interface.
I hope this helped!
This is described in the PHPDoc standards
https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md#713-param
/**
* Initializes this class with the given options.
*
* #param array $options {
* #var bool $required Whether this element is required
* #var string $label The display name for this element
* }
*/
public function __construct(array $options = array())
{
<...>
}
In PHP, I've seen a very nice way of doing this:
#return array<Thing,OtherThing,SomethingElse>
IDEs like PHPStorm and VSCode understand this syntax pretty well. Hope this helps.
Let's say that I have a function that returns array $data with a User object $user and a Car object $car
function my_function(){
return array(
new User(),
new Car()
);
}
What should I use for my #return parameter for the function documentation?
I Would do it this way
/**
* #return User[]|Car[]
*/
General | means or and SomeType[] means there is an array of SomeType
Are you Sure, you did not want this?
/**
* My Parent Object
*/
class SomeClass {
/**
* The User
* #var User
*/
public $User;
/**
* The Car
* #var Car
*/
public $Car;
}
The good (evil) thing about PHP is, you can mix array types. In a strong Typed Language (for reason) you can not. Here we use Interfaces and something like this. What we try with PHPDoc is to strong type PHP. So you should play the rules of a strong typed language.
Is there anyway to give text editors summary information in a tooltip for custom functions/classes etc. in the way that they can do for standard libraries while coding?
Failing this what is the standard way to highlight the purpose, required params etc. for a function/class in PHP.
Check out PHPDocumentor.
An example would be:
/**
* Set the data
*
* #access public
* #param string $field
* #param mixed $value
*/
public function __set($field, $value)
{
$this->_data[$field] = $value;
}
/**
* Get the data
*
* #access public
* #param string $field
* #return mixed
*/
public function __get($field)
{
return isset($this->_data[$field]) ? $this->_data[$field] : NULL;
}
As the comments self-explain, you use #access to show the visibility of the method (if the code being summarized is a method, of course), #paramto show each parameter, and #return to show the type of the data being returned. There are many different tags to document many different aspects of the code.
You can use the PHPDoc standard for letting your IDE give you hints about, for example, a function.
Just before a function declaration you could have:
/**
* This is a DocBlock comment
*/
function foo(){
//....
}
I've used it in Netbeans and can say that it works quite nicely.
Let's say I have a PHP class called Color, it's constructor accepts various params.
// hex color
$myColor = new Color('#FF008C');
// rgb channels
$myColor = new Color(253,15,82);
// array of rgb channels
$myColor = new Color(array(253,15,82));
// X11 color name
$myColor = new Color('lightGreen');
How should I use phpDoc to create API documentation for constructor and other methods like this?
How to use phpDoc with overloaded methods?
class Color {
/**
* Constructor
* what should be here?
*/
public function __construct() {
/* CODE */
}
}
Just my point of view, but you should not have multiple constructors in the first place - your constructor is going to be full of if/else-ladders, which really isn't a good idea, especially for something lightweight like a representation of a Color.
I strongly encourage you to try something like this instead:
class Color
{
protected function __construct($r, $g, $b)
{ ... }
public static function fromHex($hex) {
return new Color(...);
}
public static function fromRGB($r, $g, $b) { ... }
public static function fromArray(array $rgb) { ... }
...
}
Now, in consumer code, instead of somewhat mysterious and ambiguous constructor calls like these:
$a = new Color(0,0,0);
$b = new Color('#000000');
Instead you can have more legible and semantic consumer code, like this:
$a = Color::fromRGB(0,0,0);
$b = Color::fromHex('#000000');
This probably makes more sense to somebody reading the consumer code, it eliminates the logic required to make the ambiguous constructor work, and as a bonus (if you're using an IDE such as PhpStorm) you can have all your inspections pass. If you're running a documentation generator, this also ensures that all the options are documented individually, rather than lumped together in a verbal description.
Note that I declared the constructor protected - this is a personal preference, but if I'm going to have multiple static factory-methods, I prefer to see those consistently used in consumer code, rather than sometimes seeing Color::fromRGB(...) and other times new Color(...).
I think that is better to use #method annotation for class/interface, which declares overloading methods. This question is interesting for me too.
/**
* #method void setValue(int $value)
* #method void setValue(string $value)
* #method void setValue(string $value, int $startFrom)
*/
class Example
{
public function setValue($arg1, $arg2)
{
// ...
}
}
See http://phpdoc.org/docs/latest/references/phpdoc/tags/method.html
Because you allow variable length arguments there are two ways I would do this.
I would simply list the allowed arguments are parameters.
/**
* #param mixed $arg1 ... description
* #param mixed $arg2 ... description
* #param mixed $arg3 ... description
*/
public function __construct() {}
Or I would simply provide an explanation with some examples.
/**
* Explanation of different expected argument combinations.
*/
public function __construct() {}
Another alternative, since only one of the examples has more than one argument, would be to simply define the arguments in the method signature making the last 2 optional. Like this:
/**
* #param mixed $arg1 ...
* #param int $arg2 ...
* #param int $arg3 ...
*/
public function __construct($arg1, $arg2 = null, $arg3 = null) {}
I know of no elegant way to do this with phpDoc. The phpDoc comment/api formatting is based on a the Javadoc format. Javadoc doesn't have a feature set to support this because in java, if you want a method to have a variable number of arguments you re-declare the method prototype for each variation.
public double foo() {
}
public double foo(double my_param) {
}
So, my performance preference is to do something like
/**
* My General description
*
* Here explain what each argument combination can do
* #param mixed $arg1 can be array, string, hex as string, or int
* #param int $arg2 if arg1 is int, then this is etc, otherwise optional
* #param int $arg3 if ar1 is int, then this is etc, otherwise optional
*/
but this may not play nice with the various auto-documentation tools.
The according to Hoyle way to accomplish this can be found at the phpDoc site.