I want to learn about PHP Anotations - php

What is PHP Anotations and where can I learn more about it? I need simple example to understand it. I have googled around alot. Somehow i reached this point:
Example Code:
<?php
class AddressShipment{
/* Attributes of AddressShipment */
/**
* private TypePlaceShipment type
* #ORM\Id #ORM\Column #ORM\GeneratedValue
* #dummy
* #var long
*/
private $type;
/**
* private boolean lift
* #ORM\Column(type="boolean")
* #Assert\NotEmpty
* #var boolean
*/
private $lift;
/**
* private String comment
* #ORM\Column(type="string")
* #Assert\NotEmpty
* #var string
*/
private $comment;
?>
Can someone explain this a bit ? What are PHP Anotations? How can we use it ? What is the purpose of using it ?

It is basically for documentation generation.
Also IDEs which support php look up the annotations and give you information on what the function does, what it returns, what parameter it takes.
So if you make a php library, another person can read the annotations easily to know what it does without having to dig through your code and his IDE will recognize those annotations
here is an example of netbeans using this annotation from a function somewhere
You can learn by visiting this link:
http://manual.phpdoc.org/HTMLSmartyConverter/PHP/phpDocumentor/tutorial_elements.pkg.html

Aside from providing documentation (e.g. http://www.phpdoc.org/ ) and providing hints for the IDE, some libraries use annotations to determine how to handle classes. One example is Doctrine which provides an Object Relational Mapper that can map objects to a database based on annotations (using its database abstraction layer).
In the given code fragment I recognize #ORM\Id, #ORM\Column and #ORM\GeneratedValue as some of the annotations that Doctrine uses. However, AddressShipment is not declared as an Entity with the appropriate annotation, so they're not correctly used for that purpose.
Zend Framework 2 utilizes Doctrine's annotation library to enable the creation of forms from annotations (including validations and filtering).
Under the hood Doctrine uses reflection to read these annotations. If you use annotation-dependent libraries in combination with certain PHP accelerators, then you need to take care to configure the accelerator not to discard the annotations when it caches the code.

(Take note before reading that in fact I know you are talking about how to use some php ORM framework documentation tags and where to find what they mean).
Annotations are just annotations in PHP world they are called "PHPDoc Tags" but unfortunately they are used for nothing more than some PHP IDE code autocompletion / intellisense / documentation generation.
PHPDoc by itself is a standard that raised from nowhere but opensource php documentation project many years ago and was positively received from php community and now even php reflection class supports them.
For example phpdoc tag #return specifies what will be php class method return type or php function return type.
#var specifies what is property type. PHPDoc has its own declaration rules. For example documentation must begin with /** and must and with */. You can find this standards on http://en.wikipedia.org/wiki/PHPDoc#Tags link.
In example below all tags with # symbol are legal and might be treated by some PHP IDE like Netbeans or Eclipse or even Sublime sometimes. But:
class planet
{
/**
* primary
* length 16
* #var string
*/
public $name;
/**
* type smallint
* #var integer
*/
public $order;
/**
* #var boolean
*/
public $water;
/**
* #var \galaxy\star
*/
public $star;
/**
* enum
* #var \galaxy\moon
*/
public $moons = array ();
But what is interesting in your question is that you also mentioned #ORM. This means you are using some ORM framework probably Doctrine with Symphony and you need to find what does these annotations mean for specific framework. This can be found easily in specific framework's documentation. They are so many that there is no clue to post them on here.
For example if you are planning to use Doctrine you can visit here http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html
Or if you are using single file framework db.php which is database first style also and uses annotations as well you can visit here http://dbphp.net.

Related

Is there any way of using an object type in #property-read and "declare" its attributes?

I want to add a type of object in #property-read and also be able to access its attributes with PhpStorm suggestions.
Here's what I would like to do:
/**
* #property-read object{type: string, schema: string} $request_schema
* #property-read object{type: string, schema: string} $response_schema
*/
class ConfigApiRoutesSchema extends BaseSchema
{
...
}
The reason I'm doing this is because I want to access the attributes type and schema, like this:
$configApiRoutesSchema = new ConfigApiRoutesSchema();
$configApiRoutesSchema->request_schema->type // Here's the problem, type is not suggested
$configApiRoutesSchema->request_schema->schema // schema is also not suggested
This is exactly what I need, but unfortunately this doesn't work for some reason. One solution is to create two classes and specify them as types:
/**
* #property-read string $type
* #property-read string $schema
*/
class RequestSchema {}
/**
* #property-read string $type
* #property-read string $schema
*/
class ResponseSchema {}
/**
* #property-read RequestSchema $request_schema
* #property-read ResponseSchema $response_schema
* #
*/
class ConfigApiRoutesSchema extends BaseSchema {}
Now PhpStorm suggests both schema and type.
But it doesn't seem correct, since RequestSchema and ResponseSchema won't actually be used. So I wonder if there's any way of using annotation with objects without having to create a class to suggest its attributes.
Thank you.
Altho it is possible to specify the shape of arrays, for objects it is not possible to do so (yet). Such a syntax would have been be specified in PSR-5 and PSR-19, but this is not the case.
In the same manner it is not possible to specify the properties of a returned plain object from a method with the #return object annotion.
Apparently the syntax is supported by Psalm, but not in PhpStorm (at very least not yet).
Currently there is a public proposal on the PhpStorm YouTrack board. You might want to upvote that issue to increase it's chance of being included in the next PhpStorm version.

Symfony : is it bad practice to add custom functions in an Entity?

I understand that an Entity is a basic class that holds data.
But is it bad practice if the Entity has custom functions that manipulates the data ?
I personally think that this kind of functions should go into a different Service. But in this case, the getNextPayroll is quite useful :
<?php
class Payroll
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="last_payroll", type="datetime", nullable = true)
*/
private $lastPayroll;
/**
* Set lastPayroll
*
* #param \DateTime $lastPayroll
* #return CompanyBase
*/
public function setLastPayroll($lastPayroll)
{
$this->lastPayroll = $lastPayroll;
return $this;
}
/**
* Get lastPayroll
*
* #return \DateTime
*/
public function getLastPayroll()
{
return $this->lastPayroll;
}
public function getNextPayroll()
{
$payrollNext = clone $this->getLastPayroll();
$payrollNext->add(new \DateInterval("P1M"));
return $payrollNext;
}
}
The date of the next payroll is not stored in database. Only the date of the last payroll. Should I get the next payroll date in a different service or is it OK to use use a custom function non-generated by doctrine in an entity ?
It's not a bad practice, if your code still satisfies SOLID principles (mainly, Single Responsibility principe in that case)
So, if the method isn't related to entity logic (for example, sending emails or persisting something to database right from your entity) -- it's wrong. Otherwise, it's absolutely OK.
The major attribute of the logic related to entity -- it should be in the same layer with another stuff in the entity.
Actually, Doctrine entities is not just Data Transfer Objects (without behavior). Doctrine's developers insist using the entities as Rich Models (look the video by Marco Pivetta, one of Doctrine's developers and see his nice presentation)
As far as I know it shouldn't be bad practice as long as your entity doesn't get into the Database layer, which the Repository should take care of.
So things where you more or less just get EntityData back (like your method which returns just modified data that belongs to the Entity) should be fine in the Entity it self. This way you also easily use the methods inside Twig, which automaticaly searchs for the method name (ex. {{ User.name }} will search for User->getName() and if it doesn't find it, it will search for User->name())
If you reusing this part and want to be dynamic, it also could be a good idea to create a custom Twig extension.
I think you will only need a service if you going to do very complicated things where you actually also need to inject the EntityManager and also retrive data from other entities that maybe are not part of the usual relations.

In the Eclipse PDT, is it possible to configure content assist to look for alternative tags to suggest PHP types?

I'm working on a project that uses the Lithium (http://li3.me/) framework and they document their classes like this:
class Controller extends \lithium\core\Object {
/**
* Contains an instance of the `Request` object with all the details of the HTTP request that
* was dispatched to the controller object. Any parameters captured in routing, such as
* controller or action name are accessible as properties of this object, i.e.
* `$this->request->controller` or `$this->request->action`.
*
* #see lithium\action\Request
* #var object
*/
public $request = null;
I've always used fully qualified class names in the #var and Eclipse seems to do a good job with that for generating content assist. However they seem to document class names using #see tags instead, and content assist is not available. Is there a way to configure PDT to use the information in the #see tag as a class name for the purposes of content assist?
It's not possible without own plugin. #see tag should be used for links only.

How to use phpDocumentor for CodeIgniter

I've built quite an extensive web application and I was looking through the style guide for CodeIgniter (CI) to see how to do comments. It has things like this for classes and methods:
/**
* Super Class
*
* #package Package Name
* #subpackage Subpackage
* #category Category
* #author Author Name
* #link http://example.com
*/
class Super_class {}
/**
* Encodes string for use in XML
*
* #access public
* #param string
* #return string
*/
function xml_encode($str){}
This is fine but then I don't know what to fill out for these options. I don't really have #package, I just have some models and controllers. In Java I might use packages for security but not in CI, it's just the MVC. I always have things like, project_mode, projects (controller) and add_project_view.php for example.
Also what is the format for #category? The phpDocumentor docs say, "The #category tag is used to organize groups of packages together". Again, no packages!
Secondly, what about parameters in methods? Sometimes I have two strings and an array or an integer and an array, what is the format for #param?
Thanks,
Package, subpackage and category are for better structuring your code logically. It doesn't need to be there for every project/code file you have.
Params in methods on the other hand are very useful to be defined, because we need to know what they are when reading the documentation because we need to pass them while calling those methods in our code.
A sample would be like so:
/**
* Sample function
* #param string $param1 name of person
* #param integer $param2 age of person
* #return string
*/
function person($name, $age)
{
return "$name is $age years old";
}
#package can only be used to document procedural pages or classes.
Packages are used to help you logically group related elements. You
write classes to group related functions and data together, and
phpDocumentor represents the contents of files (functions, defines,
and includes) as "Procedural Pages." A package is used to group
classes and procedural pages together in the same manner that a
directory groups related files together.
You can find answers to your questions and more in phpDocumentor guide here

How to set member type in Doxygen for PHP code?

I'm trying to document PHP class members with Doxygen (I'm not using PHPDocs because the project involves COCOA programming, so I can use the same tool for both parts).
/**
* This is brief description.
*
* This is detailed description.
*/
private $foo;
This code gets the documentation done right, but I would like to include in the docs the type the var should handle.
I tried to use \var and \property, but then Doxigen does not generate the doc for the var.
//THIS IS NOT WORKING!
/**
* This is brief description.
*
* This is detailed description.
* \var int
*/
private $foo;
I have seen this post:
Doxygen: how to describe class member variables in php?
Seems that \var is not working in Doxyegn, but the post is a bit old and maybe there is something I can do now.
I have follow the bug comments of this feature:
https://bugzilla.gnome.org/show_bug.cgi?id=626105.
In comment number 6 a solution is proposed, adding the var name after the type.
class Mine {
/**
* Definition of variable
* #var string $var
*/
private $var = array();
}
This is working for me.
Simple workaround which generates acceptable results is to add this input filter:
INPUT_FILTER = "sed -e 's/#var\s/#see /'"
Or even better to define an alias:
ALIASES += "var=#see"
It simply replaces #var command with #see command. It is not perfect, but it is very simple and relatively bulletproof.
Small disadvantage is that the type is somewhere in the description instead of the heading. On the other side, if only few properties has type defined, it makes documentation more consistent (headings look the same).
#type works for me:
/** #type string[] */
private $csvData;
/**
* command line parameters
* #type string[]
*/
private $parameters;

Categories