Reorder PHPDoc / Symfony annotations with csfixer - php

Is there a way with php-cs-fixer to define an order for Symfony annotations/PHPDoc ?
Here is two examples of a controller method and an entity property :
/**
* #Security()
*
* #ParamConverter()
*
* #Rest\Post()
* #Rest\View()
*
* #param Request $request
* #param xxxInterface $item
*
* #return \FOS\RestBundle\View\View
*/
public function myAction(Request $request, xxxInterface $item)
and
/**
* #var itemInterface
* #ORM\ManyToOne()
* #ORM\JoinColumn()
* #JMS\Groups()
* #JMS\AccessType()
* #MyCustomAssert\Assert1
*/
protected $item;
For methods, I want to set the order to #Security, #ParamConverter, #Rest then PHPDoc and for properties, I always want #MyCustomAssert at the end.
Is this something possible with php-cs-fixer ?

I think it isn't possible with php-cs-fixer (https://mlocati.github.io/php-cs-fixer-configurator/?version=2.9#version:2.15 might help searching)
However the slevomat coding standard for php code sniffer includes a sniff "SlevomatCodingStandard.Commenting.DocCommentSpacing" which allows you to configure annotationsGroups
The phpcbf script can reorder your annotations using this snif.

Related

How to use SearchFilter using a dbRef with Api_Platform?

When I have a document property using a dbRef - relation like this:
/**
* #MongoDB\ReferenceOne (
* discriminatorMap={
* "post"=Post::class
* },
* defaultDiscriminatorValue="post",
* storeAs="dbRef",
* inversedBy="references",
* cascade={"persist"}
* )
*/
protected DocumentInterface $target;
How can I apply the built-in SearchFilter from Api_Platform to return all items with a matching dbRef and what would the adequate Request look like?
I have now implemented a workaround myself by creating a custom dbRef-Filter to add a filter for existing references to the AggregationBuilder.
$aggregationBuilder->match()->field($property)->references($document);

Remove cache files in Laravel

I am beginner in Laravel.
I use in my project Laravel 7.
I have cache system in my project.
I have cache in my project with keys:
category
category.id
category.subcategory.id
product.all
etc.
I need function to remove cache.
I write this:
private function deleteCache(string $keyToRemove)
{
Cache::forget($keyToRemove);
}
Is universal cache removal possible?
I need a function that will be
Remove selected keys:
deleteCache(['category.100', 'product.all', 'category.1'])
Remove all cache with category (for example: category.1, category.all, category, category.tree, category.subcategory.1 etc).
deleteCache(['category.*'])
How can I make it?
TL:DR What you need is not available by default, you need customized, wrapper methods that requires "technical" knowledge about the cache driver(underlying technology) you choose.
Laravel cache supports multiple technologies(drivers) including redis, database, file, memcached etc. All these drivers implement the same interface.
namespace Illuminate\Contracts\Cache;
interface Store
{
/**
* Retrieve an item from the cache by key.
*
* #param string|array $key
* #return mixed
*/
public function get($key);
/**
* Retrieve multiple items from the cache by key.
*
* Items not found in the cache will have a null value.
*
* #param array $keys
* #return array
*/
public function many(array $keys);
/**
* Store an item in the cache for a given number of minutes.
*
* #param string $key
* #param mixed $value
* #param float|int $minutes
* #return void
*/
public function put($key, $value, $minutes);
/**
* Store multiple items in the cache for a given number of minutes.
*
* #param array $values
* #param float|int $minutes
* #return void
*/
public function putMany(array $values, $minutes);
/**
* Increment the value of an item in the cache.
*
* #param string $key
* #param mixed $value
* #return int|bool
*/
public function increment($key, $value = 1);
/**
* Decrement the value of an item in the cache.
*
* #param string $key
* #param mixed $value
* #return int|bool
*/
public function decrement($key, $value = 1);
/**
* Store an item in the cache indefinitely.
*
* #param string $key
* #param mixed $value
* #return void
*/
public function forever($key, $value);
/**
* Remove an item from the cache.
*
* #param string $key
* #return bool
*/
public function forget($key);
/**
* Remove all items from the cache.
*
* #return bool
*/
public function flush();
/**
* Get the cache key prefix.
*
* #return string
*/
public function getPrefix();
}
Depending on the driver you choose - you need customized methods to achieve what you need.
For your first question, the following method would be useful to remove multiple keys.
public function deleteCache(array $keys)
{
foreach ($keys as $key) {
Cache::forget($key);
}
}
I am familiar with redis so i will give examples around it. If you are going to use redis as cache driver - it is better to modify that method like this; Since redis's delete command supports deleting multiple keys at once. This one is more effective than the previous one.
public function deleteCache(array $keys)
{
Redis::del($keys);
}
One trick is to be careful about cache prefix. If you are using cache prefix(defined in your cache config file) - then you need to prepend those prefix to keys.
For your second question(Remove all cache with category) there are several ways to do it but some of them wouldn't be performance/production friendly. In redis you may execute some command such as keys or scan to iterate through database and then invoke the previously defined method with the returned results.
Especially keys command should only be used in production environments with extreme care.
redis key
redis scan
Redis is only example - if you are going to use database cache driver - then you need to implement methods to satisfy your case. It will require technical knowledge about the both how laravel implements it via database(tables, queries etc) and how your extended methods will use it(tables, queries, columns, indexes etc)

How to quickly contain pluralization failure in API Platform?

Built-in Symfony pluralization sometimes fails and API Platform relying on it builds the resource paths incorrectly (at least not the way I'd like them to be built).
For example: There's an English Dictionary API containing Entries and each Entry resource may have a PartOfSpeech subresource. In fact multiple PartS of Speech.
/**
* #ApiResource
* #ORM\Entity
*/
class Entry {
// ...
/**
* #var PartOfSpeech[]
*
* #ORM\OneToMany(targetEntity="PartOfSpeech", mappedBy="entry")
* #ApiSubresource
*/
public $partsOfSpeech;
}
/**
* #ApiResource
* #ORM\Entity
*/
class PartOfSpeech {
// ...
/**
* #var Entry
*
* #ORM\ManyToOne(targetEntity="Entry", inversedBy="partsOfSpeech")
*/
public $entry;
}
So, while I'd like the path to be parts_of_speech, API Platform will generate part_of_speeches or even parts_of_speeches (in case of the subresource) for the obvious reason. I know I can substitute paths operation by operation: collectionOperations={"get"={"path"="/parts_of_speech/{id}"}}. But I consider it a bit ugly and inconvenient. Is it possible to enforce a different path in a more elegant way? Preferably in one place per resource. And how to change a path of a subresource?
--
Clarification:
I can almost solve it as:
/**
* #ApiResource(
* collectionOperations={
* "get"={"path"="/parts_of_speech"},
* "post"={"path"="/parts_of_speech"},
* },
* itemOperations={
* "get"={"path"="/parts_of_speech/{id}"},
* "delete"={"path"="/parts_of_speech/{id}"},
* "put"={"path"="/parts_of_speech/{id}"},
* "patch"={"path"="/parts_of_speech/{id}"},
* },
* )
* #ORM\Entity
*/
class PartOfSpeech
{
It almost does the job but: 1. It's ugly so I ask if there is a shorter, more elegant solution; 2. Even if I write like this, I still don't know how to fix the plural in case of subresource. The following (a guess based on the documentation) doesn't work:
/**
* #ApiResource(
* subresourceOperations={
* "part_of_speech_get_subresource"={"path"="/entries/{id}/parts_of_speech"},
* }
* )
* #ORM\Entity
*/
class Entry
{
and still renders: /entries/{id}/parts_of_speeches
To do so you can use the routePrefix attribute:
/**
* #ApiResource(routePrefix="/parts_of_speech")
*/
class Entity
{
}

Doctrine issue (mappings inconsistent)

I'm busy with a project in Symfony and I'm just checking the profiler tab and seeing 2 errors continuously popping up - they are below.
The mappings MyBundle\MainBundle\Entity\School#provinceId and MyBundle\MainBundle\Entity\Province#schools are incosistent with each other.
The association MyBundle\MainBundle\Entity\School#grades refers to the owning side field MyBundle\MainBundle\Entity\Grade#school_id which does not exist.
I'm getting a couple more of these and I can't understand why? What does it mean by "incosistent" (see what I did there)? Parts of my code is below if it's helpful.
In Province.php
/**
* #ORM\OneToMany(targetEntity="School", mappedBy="provinceId")
*/
private $schools;
and in my Schools.php
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Province", inversedBy="schools")
* #ORM\JoinColumn(name="province_id", referencedColumnName="id")
*/
private $provinceId;
And for the second error...
School.php
/**
* #ORM\OneToMany(targetEntity="Grade", mappedBy="school_id")
*/
private $grades;
and Grade.php
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="School", inversedBy="grades")
* #ORM\JoinColumn(name="school_id", referencedColumnName="id")
*/
private $schoolId;
I just want to know what these errors mean exactly and why these entities aren't right - I tried following the docs off the doctrine page but apparently I went wrong somewhere!
Thanks for any help!
I don't have your entire configuration, so I'm just going to make an educated guess here... (forgive me if I'm wrong!)
Regarding the first one, you say the mapping looks like this:
# Province.php
/**
* #ORM\OneToMany(targetEntity="School", mappedBy="provinceId")
*/
private $schools;
# School.php
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="Province", inversedBy="schools")
* #ORM\JoinColumn(name="province_id", referencedColumnName="id")
*/
private $provinceId;
I imagine it's the types that are throwing things off here. You see, the purpose of the mappings is so that you can treat these things like objects, without having to worry about how they're persisted/connected in the database. Specifically, in your case, a School entity should not have a member $provinceId of type integer; rather, it should have a $province of type Province.
Try this:
# Province.php
/**
* #ORM\OneToMany(targetEntity="School", mappedBy="province")
*/
private $schools;
# School.php
/**
* #var Province
*
* #ORM\ManyToOne(targetEntity="Province", inversedBy="schools")
* #ORM\JoinColumn(name="province_id", referencedColumnName="id")
*/
private $province;
(Again, this is wholly untested, and I only have a part of what you have... but I think this will get you closer.)

PHP function comments

I've seen that some PHP functions are commented at the top, using a format that is unknown to me:
/**
*
* Convert an object to an array
*
* #param object $object The object to convert
* #return array
*
*/
My IDE gives me a dropdown selection for the things such as #param and #return, so it must be documented somewhere. I've tried searching google but it won't include the # symbol in its search.
What is this format of commenting and where can I find some information on it?
Functions:
/**
* Does something interesting
*
* #param Place $where Where something interesting takes place
* #param integer $repeat How many times something interesting should happen
*
* #throws Some_Exception_Class If something interesting cannot happen
* #author Monkey Coder <mcoder#facebook.com>
* #return Status
*/
Classes:
/**
* Short description for class
*
* Long description for class (if any)...
*
* #copyright 2006 Zend Technologies
* #license http://www.zend.com/license/3_0.txt PHP License 3.0
* #version Release: #package_version#
* #link http://dev.zend.com/package/PackageName
* #since Class available since Release 1.2.0
*/
Sample File:
<?php
/**
* Short description for file
*
* Long description for file (if any)...
*
* PHP version 5.6
*
* LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_01.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license#php.net so we can mail you a copy immediately.
*
* #category CategoryName
* #package PackageName
* #author Original Author <author#example.com>
* #author Another Author <another#example.com>
* #copyright 1997-2005 The PHP Group
* #license http://www.php.net/license/3_01.txt PHP License 3.01
* #version SVN: $Id$
* #link http://pear.php.net/package/PackageName
* #see NetOther, Net_Sample::Net_Sample()
* #since File available since Release 1.2.0
* #deprecated File deprecated in Release 2.0.0
*/
/**
* This is a "Docblock Comment," also known as a "docblock." The class'
* docblock, below, contains a complete description of how to write these.
*/
require_once 'PEAR.php';
// {{{ constants
/**
* Methods return this if they succeed
*/
define('NET_SAMPLE_OK', 1);
// }}}
// {{{ GLOBALS
/**
* The number of objects created
* #global int $GLOBALS['_NET_SAMPLE_Count']
*/
$GLOBALS['_NET_SAMPLE_Count'] = 0;
// }}}
// {{{ Net_Sample
/**
* An example of how to write code to PEAR's standards
*
* Docblock comments start with "/**" at the top. Notice how the "/"
* lines up with the normal indenting and the asterisks on subsequent rows
* are in line with the first asterisk. The last line of comment text
* should be immediately followed on the next line by the closing asterisk
* and slash and then the item you are commenting on should be on the next
* line below that. Don't add extra lines. Please put a blank line
* between paragraphs as well as between the end of the description and
* the start of the #tags. Wrap comments before 80 columns in order to
* ease readability for a wide variety of users.
*
* Docblocks can only be used for programming constructs which allow them
* (classes, properties, methods, defines, includes, globals). See the
* phpDocumentor documentation for more information.
* http://phpdoc.org/tutorial_phpDocumentor.howto.pkg.html
*
* The Javadoc Style Guide is an excellent resource for figuring out
* how to say what needs to be said in docblock comments. Much of what is
* written here is a summary of what is found there, though there are some
* cases where what's said here overrides what is said there.
* http://java.sun.com/j2se/javadoc/writingdoccomments/index.html#styleguide
*
* The first line of any docblock is the summary. Make them one short
* sentence, without a period at the end. Summaries for classes, properties
* and constants should omit the subject and simply state the object,
* because they are describing things rather than actions or behaviors.
*
* Below are the tags commonly used for classes. #category through #version
* are required. The remainder should only be used when necessary.
* Please use them in the order they appear here. phpDocumentor has
* several other tags available, feel free to use them.
*
* #category CategoryName
* #package PackageName
* #author Original Author <author#example.com>
* #author Another Author <another#example.com>
* #copyright 1997-2005 The PHP Group
* #license http://www.php.net/license/3_01.txt PHP License 3.01
* #version Release: #package_version#
* #link http://pear.php.net/package/PackageName
* #see NetOther, Net_Sample::Net_Sample()
* #since Class available since Release 1.2.0
* #deprecated Class deprecated in Release 2.0.0
*/
class Net_Sample
{
// {{{ properties
/**
* The status of foo's universe
* Potential values are 'good', 'fair', 'poor' and 'unknown'.
* #var string $foo
*/
public $foo = 'unknown';
/**
* The status of life
* Note that names of private properties or methods must be
* preceeded by an underscore.
* #var bool $_good
*/
private $_good = true;
// }}}
// {{{ setFoo()
/**
* Registers the status of foo's universe
*
* Summaries for methods should use 3rd person declarative rather
* than 2nd person imperative, beginning with a verb phrase.
*
* Summaries should add description beyond the method's name. The
* best method names are "self-documenting", meaning they tell you
* basically what the method does. If the summary merely repeats
* the method name in sentence form, it is not providing more
* information.
*
* Summary Examples:
* + Sets the label (preferred)
* + Set the label (avoid)
* + This method sets the label (avoid)
*
* Below are the tags commonly used for methods. A #param tag is
* required for each parameter the method has. The #return
* and #access tags are mandatory. The #throws tag is required if
* the method uses exceptions. #static is required if the method can
* be called statically. The remainder should only be used when
* necessary. Please use them in the order they appear here.
* phpDocumentor has several other tags available, feel free to use
* them.
*
* The #param tag contains the data type, then the parameter's
* name, followed by a description. By convention, the first noun in
* the description is the data type of the parameter. Articles like
* "a", "an", and "the" can precede the noun. The descriptions
* should start with a phrase. If further description is necessary,
* follow with sentences. Having two spaces between the name and the
* description aids readability.
*
* When writing a phrase, do not capitalize and do not end with a
* period:
* + the string to be tested
*
* When writing a phrase followed by a sentence, do not capitalize the
* phrase, but end it with a period to distinguish it from the start
* of the next sentence:
* + the string to be tested. Must use UTF-8 encoding.
*
* Return tags should contain the data type then a description of
* the data returned. The data type can be any of PHP's data types
* (int, float, bool, string, array, object, resource, mixed)
* and should contain the type primarily returned. For example, if
* a method returns an object when things work correctly but false
* when an error happens, say 'object' rather than 'mixed.' Use
* 'void' if nothing is returned.
*
* Here's an example of how to format examples:
* <code>
* require_once 'Net/Sample.php';
*
* $s = new Net_Sample();
* if (PEAR::isError($s)) {
* echo $s->getMessage() . "\n";
* }
* </code>
*
* Here is an example for non-php example or sample:
* <samp>
* pear install net_sample
* </samp>
*
* #param string $arg1 the string to quote
* #param int $arg2 an integer of how many problems happened.
* Indent to the description's starting point
* for long ones.
*
* #return int the integer of the set mode used. FALSE if foo
* foo could not be set.
* #throws exceptionclass [description]
*
* #access public
* #static
* #see Net_Sample::$foo, Net_Other::someMethod()
* #since Method available since Release 1.2.0
* #deprecated Method deprecated in Release 2.0.0
*/
function setFoo($arg1, $arg2 = 0)
{
/*
* This is a "Block Comment." The format is the same as
* Docblock Comments except there is only one asterisk at the
* top. phpDocumentor doesn't parse these.
*/
if ($arg1 == 'good' || $arg1 == 'fair') {
$this->foo = $arg1;
return 1;
} elseif ($arg1 == 'poor' && $arg2 > 1) {
$this->foo = 'poor';
return 2;
} else {
return false;
}
}
// }}}
}
// }}}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* c-hanging-comment-ender-p: nil
* End:
*/
?>
Source: PEAR Docblock Comment standards
That's PHPDoc syntax.
Read more here: phpDocumentor
You can get the comments of a particular method by using the ReflectionMethod class and calling ->getDocComment().
http://www.php.net/manual/en/reflectionclass.getdoccomment.php
You must check this: Docblock Comment standards
Sample File (including Docblock Comment standards)

Categories