How can I document randomly-assigned properties of a custom type in JSDoc? - jsdoc

/**
* #typedef {string} UUID
* */
/**
* #typedef {Object} ITEM
* #property {UUID} id
* */
/**
* #typedef {Object} THINGY
* #property {??????}
* */
const oneThingy = {
asdf: {id: 'asdf', ...},
sdfg: {id: 'sdfg', ...},
dfgh: {id: 'dfgh', ...}
}
Assuming that a THINGY can have infinite k:v pairs, and that the keys will be random UUIDs, how would I document and type the #property?

Thanks to a kind person named Kyriakos on the JSDoc Slack channel, TIL it's not the #property, I just need the properly-formatted #typedef:
/**
* #typedef {string} UUID
* */
/**
* #typedef {Object} ITEM
* #property {UUID} id
* */
/**
* #typedef {Object.<UUID, ITEM>} THINGY // <-- this one
* */
const oneThingy = {
asdf: {id: 'asdf', ...},
sdfg: {id: 'sdfg', ...},
dfgh: {id: 'dfgh', ...}
}

Related

Nelmio API doc bundle post request with boolean always returns true

I'm developping a Symfony 4 API REST app with Nelmio Api Doc Bundle v3.
I am sending this request :
curl -X POST "http://dev.api_events.jessie/api/event-types" -H "accept: application/json" -H "Authorization: Bearer ZmU1MTgxNzNkZjM5ZTU2NzdiODVkODgxMmE2ZmE2OWUyMjY1ZWIxYzgxMjdlOTA3NjBiODM5Yzg1NTEzNjFlYw" -H "Content-Type: application/x-www-form-urlencoded" -d "fullName=aaaaaaaaaaa&shortName=aaaaaaaaaaa&dns=aaaaaaaaaa**&mandatoryRegistration=false"**
This is the response body :
{
"id": 19,
"full_name": "aaaaaaaaaaa",
"short_name": "aaaaaaaaaaa",
"dns": "aaaaaaaaaa",
**"mandatory_registration": true,**
"places": [],
"participation_types": []
}
I have absolutely no idea why i send mandatoryRegistration=false and my response have "mandatory_registration": true.
I paste my Controller, Form, Entity code below. And the nelmio api doc and fos_rest configuration code.
Controller :
/**
* Creates a new eventType entity.
*
* #Route("/event-types", methods="POST")
* #Operation(
* tags={"event_type"},
* summary="Creates a new event type entity",
* consumes={"application/x-www-form-urlencoded"},
* #SWG\Parameter(
* name="Authorization",
* in="header",
* description="Bearer",
* required=true,
* type="string"
* ),
* #SWG\Parameter(
* name="fullName",
* in="formData",
* description="event type full name",
* required=true,
* type="string"
* ),
* #SWG\Parameter(
* name="shortName",
* in="formData",
* description="event name",
* required=true,
* type="string"
* ),
* #SWG\Parameter(
* name="dns",
* in="formData",
* description="event type dns",
* required=true,
* type="string"
* ),
* #SWG\Parameter(
* name="mandatoryRegistration",
* in="formData",
* description="is the registration mandatory?",
* required=true,
* type="boolean"
* ),
* #SWG\Response(
* response=Response::HTTP_CREATED,
* description="Event Type created",
* #Model(type=EventType::class, groups={"event_type"})
* )
* )
*
*/
public function postEventTypeAction(Request $request, EntityManagerInterface $em)
{
$event_type = new EventType();
$form = $this->createForm(EventTypeType::class, $event_type);
$form->submit($request->request->all()); // Validation des données
if ($form->isValid()) {
$em->persist($event_type);
$em->flush();
return View::create($event_type, Response::HTTP_CREATED , []);
}
else{
return View::create($form, Response::HTTP_BAD_REQUEST , []);
}
}
EventType form :
class EventTypeType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('fullName'
)
->add('shortName')
->add('dns')
->add('mandatoryRegistration')
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => EventType::class
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'event_type';
}
}
EventType entity :
class EventType
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #Groups({"event_type","place"})
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="full_name", type="string", length=255, unique=true)
* #Groups({"event_type","place","event_type_form_data"})
*/
private $fullName;
/**
* #var string
*
* #ORM\Column(type="string", length=255, unique=true)
* #Groups({"event_type","place","event_type_form_data"})
*/
private $shortName;
/**
* #var string
*
* #ORM\Column(name="dns", type="string", length=255, unique=true)
* #Groups({"event_type","event_type_form_data"})
*/
private $dns;
/**
* #var bool
*
* #ORM\Column(name="mandatory_registration", type="boolean", nullable=true)
*
* #Groups({"event_type","event_type_form_data"})
*/
private $mandatoryRegistration;
/**
* #ORM\OneToMany(targetEntity="Place", mappedBy="eventType", cascade={"persist"})
*/
private $places;
/**
* #ORM\OneToMany(targetEntity="EventTypeParticipationType", mappedBy="eventType", cascade={"persist"})
*/
private $participationTypes;
Config :
nelmio_api_doc:
documentation:
info:
title: Api Events
description: L4M Admin Events access point.
version: 1.0.0
security_definitions:
api_key:
type: apiKey
name: authorization
in: header
security:
api_key: []
sandbox:
request_format:
method: accept_header
accept_type: application/json
body_format:
formats: [ form, json ] # array of enabled body formats,
# remove all elements to disable the selectbox
default_format: form
areas: # to filter documented routes
path_patterns:
- ^/api(?!/doc$) # Accepts routes under /api except /api/doc
- ^/oauth/v2/token
fos_rest:
param_fetcher_listener: true
body_listener: true
#allowed_methods_listener: true
routing_loader: true
view:
view_response_listener: true
formats:
json: true
# exception:
# codes:
# App\Exception\MyException: 403
# messages:
# App\Exception\MyException: Forbidden area.
format_listener:
enabled: true
rules:
- { path: ^/, prefer_extension: false, fallback_format: json, priorities: [ json, xml, html ] }
I tried some debug and find out i was trying to put a string in a boolean field which always returns true ...
Here's my solution : do not send "false" in the request, instead send 0 or 1 :
Controller edit :
/* #SWG\Parameter(
* name="mandatoryRegistration",
* in="formData",
* description="is the registration mandatory?",
* required=true,
* type="integer",
* enum={0,1}
* ),

Symfony Validation with Data-Transformers

I have a form for a Product entity and I'm putting tags inside it.
I followed the documentation and used a data-transformer : the user enter a space-separated string which is exploded into a Tag collection.
I now want to validate the string that is transformed into the collection so it cannot use meta-characters.
I tried this, but it doesn't work : (cf. symfony2 entity validation regexp a-z A-Z 0-9)
//AppBundle\Entity\Product.php
/**
* #ORM\ManyToMany(targetEntity="Tag", cascade={"persist", "remove"})
* #Assert\Regex(
* pattern="/[\w\s]+/",
* match=true,
* message="Your property should match my damn regex !"
* )
* #ORM\JoinTable(
* name="contenus_tags",
* joinColumns={#ORM\JoinColumn(name="contenu_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
private $tags;
How can I make this ?
Add a validation in the tag class on its name, and a "valid" assertion on tags in your product class:
//AppBundle\Entity\Tag.php
/**
* #Assert\Regex(
* pattern="/^[a-Z0-9]+$/",
* match=true,
* message="Your property should match my damn regex !"
* )
*/
private $name;
//AppBundle\Entity\Product.php
/**
* #ORM\ManyToMany(targetEntity="Tag", cascade={"persist", "remove"})
* #Assert\Valid()
* #Assert\Regex(
* pattern="/[\w\s]+/",
* match=true,
* message="Your property should match my damn regex !"
* )
* #ORM\JoinTable(
* name="contenus_tags",
* joinColumns={#ORM\JoinColumn(name="contenu_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="tag_id", referencedColumnName="id")}
* )
*/
private $tags;

Specific form with two enities with Symfony

I have a Category entity, this entity allow me to create a tree of my data :
I would like to create a DiscountGrid entity. A DiscountGrid is composed by a textfield name, and an array containing the discount percentage by category ($discount[idCategory] = $percentage).
In fact, I would like a form like this :
The output would be $discount[ 1 ] = 25, $discount[ 2 ] = 30,.....
I have no idea how handle this behavior with Symfony framework. Here is the declaration of my entities
class Category{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="slug", type="string", length=255, nullable=true)
*/
private $slug;
/**
* #var int
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* #var int
* #Gedmo\TreeLevel
* #ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* #var int
* #Gedmo\TreeRight
* #ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\ManyToOne(targetEntity="Category")
* #ORM\JoinColumn(name="root", referencedColumnName="id", onDelete="CASCADE")
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
class DiscountGrid{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="slug", type="string", length=255)
*/
private $slug;
/**
* #var array
*
* #ORM\Column(name="grid", type="array")
*/
private $grid;
First of all, what you are trying to do will be a nightmare if you keep storing DiscountGrid::$grid as an array. Not only this will make your form creation extremely hard, but what will happen if someday you have to add a Category? Will you drag all the indexes to match the new Categories list? This was not your question, and I may be downvoted for suggesting that, but I definitely recommend you build your model a bit cleaner, since having a clean model is mandatory to use FormTypes properly.
What I would suggest is the following model:
DiscountGrid::$grid (rename it to $discounts) is a ManyToOne of a new entity called Discount.
Discount has an attribute $category which is a OneToMany towards Category and an attribute $reduction which is a float.
Once you have this, create a DiscountFormType with a single field reduction which is a PercentType.
Then, create another form DiscountGridFormType with a single field discounts as a CollectionType. This CollectionType should have the option entry_type set as DiscountFormType.
Finally, when you create your form in Controller, bind it a DiscountGrid entity with some Discounts in your discounts attribute. You should see a series of text boxes with percents at the end. That's the list of discounts where you can change values of the reductions.
After that, some form theming will help you display the category name next to the textbox. But I guess you already have some way to go before being at this point.

ManyToMany odm symfony2

I need to do this schema in symfony2 with odm, I have problems because the relasion is ManyToMany and I dont know How to do this. I need help.
I have the entity "Persona" and entity "Direccion" and these generate the entity "Persona-has-Direccion" with his ids and the attribute "viveAqui".
Persona{
_id: 1000,
nombre: 'Carlos',
apellidos: 'Gracia',
genero: 'M',
direcciones: [{
direccion_id: 1,
viveAqui: true
}.{
direccion_id: 2,
viveAqui: true
}]
}
My code:
/**
* #MongoDB\Document
*/
class Direccion
{
/**
* #MongoDB\Id(strategy="auto")
*/
private $id;
/**
* #MongoDB\String
*/
private $pais;
/**
* #MongoDB\String
*/
private $estado;
/**
* #MongoDB\String
*/
private $ciudad;
/**
* #MongoDB\Boolean
*/
private $viveAqui;
}
/**
* #MongoDB\Document
*/
class Persona
{
/**
* #MongoDB\Id(strategy="auto")
*/
private $id;
/**
* #MongoDB\String
*/
private $nombre;
/**
* #MongoDB\String
*/
private $apellidos;
/**
* #MongoDB\String
*/
private $genero;
}
Not sure what this mean:
these generate the entity "Persona-has-Direccion"
but I think basically simple reference is what you need:
class Persona
{
/**
*
* #MongoDB\ReferenceMany(targetDocument="Direccion", simple=true)
*/
protected $direcciones;
Then generate setter and getter (adder and remover in this case):
php app/console doctrine:mongodb:generate:documents YourBundle
You can save it later:
$persona = new Persona();
$direccion = new Direccion();
$persona->addDireccion($direccion);
$dm->persist($persona);
$dm->flush($persona);
Ok, I have a solution, but I dont know if it is correct.
My code:
/**
* #MongoDB\Document
*/
class Persona
{
/**
* #MongoDB\Id(strategy="auto")
*/
private $id;
/**
* #MongoDB\EmbedMany(targetDocument="PersonaDireccion")
*/
private $direccionPersona;
/**
* #MongoDB\String
*/
private $nombre;
/**
* #MongoDB\String
*/
private $apellidos;
/**
* #MongoDB\String
*/
private $genero;
}
class PersonaDireccion
{
/**
* #MongoDB\Id(strategy="auto")
*/
private $id;
/**
* #MongoDB\ReferenceOne(targetDocument="Direccion", cascade={"persist", "remove"})
*/
private $direccion;
/**
* #MongoDB\Boolean
*/
private $viveAqui;
}
/**
* #MongoDB\Document
*/
class Direccion
{
/**
* #MongoDB\Id(strategy="auto")
*/
private $id;
/**
* #MongoDB\String
*/
private $pais;
/**
* #MongoDB\String
*/
private $estado;
/**
* #MongoDB\String
*/
private $ciudad;
}
Now I have 3 documents. The document "PersonaDireccion" has referenceOne to "Direccion". The document "Persona" has embedMany "PersonaDireccion". The schema is the next:
Persona{
_id: 1000,
nombre: 'Carlos',
apellidos: 'Gracia',
genero: 'M',
direcciones: [{
direccionPersona_id: 1,
direccion_id: 1,
viveAqui: true
}.{
direccionPersona_id: 2,
direccion_id: 2,
viveAqui: true
}]
}

How to make link of method parameter type in jsDoc

Is there any natural way or special tag to make parameter type as link?
/**
* My js app
* #module app
*/
/**
* Namespace for MYAPP classes and functions.
* #namespace HUMAN_RESOURCE
*/
var HUMAN_RESOURCE = HUMAN_RESOURCE || {};
/**
* #class JustClass
* #constructor
*/
HUMAN_RESOURCE.JustClass = function(){ }
/**
* Constructs Person objects
* #class Person
* #constructor
* #param {String} First name
* #param {String} Last name
*/
HUMAN_RESOURCE.Person = function (first, last) {
/**
* First name of the Person
* #property first_name
* #type String
*/
this.first_name = first;
/**
* #property f_createPerson
* #param {Person} [_person] açıklama
* #return {Person} Person type object
*/
this.f_createPerson = function(_person, _person2){ return new Person() }
};
/**
* Return Person's full name
* #alias getName
* #memberof! HUMAN_RESOURCE.Person#
* #return {String} First name + last name
*/
HUMAN_RESOURCE.Person.prototype.getName = function () {
return this.first_name + ' ' + this.last_name;
};
Fortunately yes, it is just not always obvious what the correct name path is (but you can basically see it at the top of your generated docs)
/**
* #property f_createPerson
* #param {module:app~HUMAN_RESOURCE.Person} [_person] açıklama
* #return {module:app~HUMAN_RESOURCE.Person} Person type object
*/
this.f_createPerson = function(_person, _person2){ return new Person() }