I have functions which are return objects. I wish to put their jsdoc definitions to see their property and methods on webstorm intellisense.
How do I have to write jsdoc of below functions?
function MyOtherFunc() {
return { a:'for eg string', b:12 }
}
function MyFunc() {
var prop = MyOtherFunc();
function myMethod() {
alert( 'my method' );
}
function myOtherMethod() {
alert( 'my other method' );
}
// explicitly return public methods when this object is instantiated
return {
someMethod : myMethod,
someOtherMethod : myOtherMethod
};
}
You should be able to accomplish what you want using #namespace, #memberof and #instance.
/**
* #namespace MyFunc
*/
function MyFunc() {
var prop = MyOtherFunc();
/**
* Does myMethody things
*
* #memberof MyFunc
* #instance
*/
function myMethod() {
alert( 'my method' );
}
/**
* Does myOtherMethody things
*
* #memberof MyFunc
* #instance
*/
function myOtherMethod() {
alert( 'my other method' );
}
// explicitly return public methods when this object is instantiated
return {
someMethod : myMethod,
someOtherMethod : myOtherMethod
};
}
If MyFunc has any static methods, you would just leave off #instance or explicitly mark it with #static.
/**
* Say hello
*
* #param {string} [name] - Who to say hello to
* #memberof MyFunc
* #static
*/
MyFunc.helloWorld = function (name) {
console.log('Hello ' + (name || 'world'));
}
In this case, using #memberof and #static should be optional. The parser should be able to figure that out on its own; but, you might want to explicitly use them anyway to make it obvious to anyone reading the code.
This exact case is handled properly in WebStorm without JSDoc too, but you may use closure compiler type syntax for this:
/**
* #return {{a: string, b: number}}
*/
function MyOtherFunc() {
return { a:'for eg string', b:12 }
}
Related
I'm working on a new Symfony 4 project.
I have a list of Speakers, and a list of Themes, and I have a ManyToMany relations between.
class Speakers
{
// ...
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Themes", inversedBy="speakers")
* #ORM\JoinTable(name="speakers_themes")
*/
private $themes;
/**
* Speakers constructor.
*/
public function __construct()
{
$this->themes = new ArrayCollection();
}
/**
* #return Collection|Themes[]
*/
public function getThemes(): Collection
{
return $this->themes;
}
/**
* #param Themes $theme
* #return Speakers
*/
public function addTheme(Themes $theme): self
{
if (!$this->themes->contains($theme)) {
$this->themes[] = $theme;
}
return $this;
}
/**
* #param Themes $theme
* #return Speakers
*/
public function removeTheme(Themes $theme): self
{
if ($this->themes->contains($theme)) {
$this->themes->removeElement($theme);
}
return $this;
}
}
class Themes
{
// ...
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Speakers", mappedBy="themes")
*/
private $speakers;
/**
* Themes constructor.
*/
public function __construct()
{
$this->speakers = new ArrayCollection();
}
/**
* #return Collection|Speakers[]
*/
public function getSpeakers(): Collection
{
return $this->speakers;
}
/**
* #param Speakers $speaker
* #return Themes
*/
public function addSpeaker(Speakers $speaker): self
{
if (!$this->speakers->contains($speaker)) {
$this->speakers[] = $speaker;
$speaker->addTheme($this);
}
return $this;
}
/**
* #param Speakers $speaker
* #return Themes
*/
public function removeSpeaker(Speakers $speaker): self
{
if ($this->speakers->contains($speaker)) {
$this->speakers->removeElement($speaker);
$speaker->removeTheme($this);
}
return $this;
}
I want to be able to filter the list of speakers, depending of the themes.
Since the list of themes is short (3 items), I thought of a select box, with the possibility of choosing a theme to filter.
But I don't know what's the best way to do this:
Build a specific form, to filter ?
class SpeakersFilterType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('themes', EntityType::class,
[
'class' => Themes::class,
'multiple' => true,
'expanded' => true
])
->add('save', SubmitType::class,
[
'label' => 'Filter'
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'method' => Request::METHOD_GET,
// 'data_class' => null,
'data_class' => Speakers::class,
]
);
}
}
I tried to build a form like you can see below.
In the configureOptions method, I specify the method to GET, and I was hoping that I can pass some get params to filter but it's not working.
I have an error:
The form's view data is expected to be an instance of class App\Entity\Speakers, but is a(n) array. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) array to an instance of App\Entity\Speakers.
If I follow the advice and put the option 'data_class' to null, I dont have an error but I'm not sure It's working, regarding the strange params it sends to the URL:
http://127.0.0.1:8000/speakers/?speakers_filter%5Bthemes%5D%5B%5D=2&speakers_filter%5Bsave%5D=&speakers_filter%5B_token%5D=ClBi9xzMrkM72niXNnkbMi1i-3gWMQ2sgfIxY0M1Pi8
Can somebody can help ? Thank you so much from a Symfony newbie.
Given are the following two entity classes
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table()
*/
class Tree
{
/**
* #ORM\Id()
* #ORM\Column(type="guid")
* #ORM\GeneratedValue(strategy="UUID")
* #var string
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="Apple", mappedBy="tree", cascade={"persist"})
* #var Collection
*/
private $apples;
public function __construct()
{
$this->setApples(new ArrayCollection());
}
public function toArray(): array
{
return [
'id' => $this->getId(),
];
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
public function getApples(): Collection
{
return $this->apples;
}
public function setApples(Collection $apples): void
{
$this->apples = $apples;
}
}
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table()
*/
class Apple
{
/**
* #ORM\Id()
* #ORM\Column(type="guid")
* #ORM\GeneratedValue(strategy="UUID")
* #var string
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Tree", inversedBy="apples")
* #var Tree
*/
private $tree;
public function toArray(): array
{
return [
'id' => $this->getId(),
];
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
public function getTree(): Tree
{
return $this->tree;
}
public function setTree(Tree $tree): void
{
$this->tree = $tree;
}
}
The database schema looks good except for apple.tree_id being nullable. Is that already an issue in this case?
I'm persisting entries like the following:
<?php
declare(strict_types = 1);
namespace App\Service;
use App\Entity\Apple;
use App\Entity\Tree;
use Doctrine\ORM\EntityManager;
class Gardener
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function plantTree(): array
{
$entityManager = $this->entityManager;
$tree = new Tree();
$blueApple = new Apple();
$redApple = new Apple();
$tree->getApples()->add($blueApple);
$tree->getApples()->add($redApple);
$entityManager->persist($tree);
$entityManager->flush();
return (array) $tree;
}
}
When executing the persist and flush there are no errors or warnings. A tree an two apple entries are beingt store, the apple.tree_id is however always null.
It seems like I have a misconfiguration on the entity classes, but am not sure what it is. I also tried adding a JoinColumn annotation #ORM\JoinColumn(name="tree_id", referencedColumnName="id"), but it did not make any difference.
What changes do I need to make, to have appe.tree_id being set properly?
Your missing the adder & remover functions on the *ToMany side.
If your using Symfony >4 then replace setApples function with:
public function addApple(Apple $apple): Tree
{
$this->apples->add($apple);
return $this;
}
public function removeApple(Apple $apple): Tree
{
$this->apples->removeElement($apple);
return $this;
}
If you're using Zend Framework 3, then replace setApples function with:
public function addApples(array $apples): Tree
{
foreach ($apples as $apple) {
if (! $this->apples->contains($apple) {
$this->apples->add($apple)
$apple->setTree($this);
}
}
return $this;
}
public function removeApples(array $apples): Tree
{
foreach ($apples as $apple) {
if($this->apples->contains($apple) {
$this->apples->remove($apple);
}
}
return $this;
}
Have a read of the Working with Association docs, which show examples and explain how to update back 'n' forth.
I have a problem using Doctrine with many to many relation when I persist my data.
I have 2 entities :
- Bloc
- Job
I retrieve my ID's before the persist with getJobs() method.
$bloc = $form->getData();
// $bloc->getJobs() works I retrieve good IDs with foreach getId()
$em->persist($bloc);
$em->flush();
My method addJob :
/**
* Add jobs
*
* #param Job $jobs
* #return Bloc
*/
public function addJob(Job $jobs)
{
$this->jobs[] = $jobs;
return $this;
}
My form:
$bloc = $em->getRepository('Acme\\Entity\\Bloc')->find($id);
$form = $this->createForm(BlocType::class, $bloc);
$form->handleRequest();
if($form->isSubmitted()) {
$bloc = $form->getData();
$em->persist($bloc);
$em->flush();
$this->addFlashMessage('edit', "Update message");
}
But the persist add new line in my job entity instead of use line already in my database.
Any idea?
I guess $jobs is a Collection of Job, so you should implements methods to handle this collection.
If your entity declarations are correct (oneToMany, ManyToOne, uni/bi directional) you should have something like this :
class Bloc
{
// ...
protected $jobs;
public function __construct()
{
$this->jobs = new Doctrine\Common\Collections\ArrayCollection();
}
public function getJobs()
{
return $this->jobs;
}
public function setJobs($jobs)
{
$this->jobs = new Doctrine\Common\Collections\ArrayCollection();
foreach ($jobs as $job) {
$this->addJob($job);
}
return $this;
}
public function addJob(Job $job)
{
if (!$this->jobs->contains($job) {
$this->jobs->add($job);
// if needed for bi directional way
// $job->setBloc($this);
}
}
public function removeJob(Job $job)
{
// if you want
}
// ...
}
I am trying to write unit tests for my middleware in Laravel. Does anyone know a tutorial, or have an example of this ?
I have been writing a lot of code, but there must be a better way to test the handle method.
Using Laravel 5.2, I am unit testing my middleware by passing it a request with input and a closure with assertions.
So I have a middleware class GetCommandFromSlack that parses the first word of the text field in my Post (the text from a Slack slash command) into a new field called command, then modifies the text field to not have that first word any more. It has one method with the following signature: public function handle(\Illuminate\Http\Request $request, Closure $next).
My Test case then looks like this:
use App\Http\Middleware\GetCommandFromSlack;
use Illuminate\Http\Request;
class CommandsFromSlackTest extends TestCase
{
public function testShouldKnowLiftCommand()
{
$request = new Illuminate\Http\Request();
$request->replace([
'text' => 'lift foo bar baz',
]);
$mw = new \App\Http\Middleware\GetCommandFromSlack;
$mw->handle($request,function($r) use ($after){
$this->assertEquals('lift', $r->input('command'));
$this->assertEquals('foo bar baz',$r->input('text'));
});
}
}
I hope that helps! I'll try to update this if I get more complicated middleware working.
To actually test the middleware class itself you can do:
public function testHandle()
{
$user = new User(['email'=>'...','name'=>'...']);
/**
* setting is_admin to 1 which means the is Admin middleware should
* let him pass, but oc depends on your handle() method
*/
$user->is_admin = 1;
$model = $this->app['config']['auth.model'];
/**
* assuming you use Eloquent for your User model
*/
$userProvider = new \Illuminate\Auth\EloquentUserProvider($this->app['hash'], $model);
$guard = new \Illuminate\Auth\Guard($userProvider, $this->app['session.store']);
$guard->setUser($user);
$request = new \Illuminate\Http\Request();
$middleware = new \YourApp\Http\Middleware\AuthenticateAdmin($guard);
$result = $middleware->handle($request, function(){ return 'can access';});
$this->assertEquals('can access',$result);
}
I thinking the best solution is just checking what happened after middleware. For example, the authentication middleware:
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate {
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
And my test unit:
<?php
class AuthenticationTest extends TestCase {
public function testIAmLoggedIn()
{
// Login as someone
$user = new User(['name' => 'Admin']);
$this->be($user);
// Call as AJAX request.
$this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
$this->call('get', '/authpage');
$this->assertEquals(200, $response->getStatusCode());
}
}
I would do it in that way.
I was working on a localization Middleware that sets the app locale based on a URI segment, e.g. http://example.com/ar/foo should set the app local to Arabic. I basically mocked the Request object and tested as normal. Here is my test class:
use Illuminate\Http\Request;
use App\Http\Middleware\Localize;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class LocalizeMiddlewareTest extends TestCase
{
protected $request;
protected $localize;
public function setUp()
{
parent::setUp();
config(['locale' => 'en']);
config(['app.supported_locales' => ['en', 'ar']]);
$this->request = Mockery::mock(Request::class);
$this->localize = new Localize;
}
/** #test */
public function it_sets_the_app_locale_from_the_current_uri()
{
$this->request->shouldReceive('segment')->once()->andReturn('ar');
$this->localize->handle($this->request, function () {});
$this->assertEquals('ar', app()->getLocale());
}
/** #test */
public function it_allows_designating_the_locale_uri_segment()
{
$this->request->shouldReceive('segment')->with(2)->once()->andReturn('ar');
$this->localize->handle($this->request, function () {}, 2);
$this->assertEquals('ar', app()->getLocale());
}
/** #test */
public function it_throws_an_exception_if_locale_is_unsupported()
{
$this->request->shouldReceive('segment')->once()->andReturn('it');
$this->request->shouldReceive('url')->once()->andReturn('http://example.com/it/foo');
$this->setExpectedException(
Exception::class,
"Locale `it` in URL `http://example.com/it/foo` is not supported."
);
$this->localize->handle($this->request, function () {});
}
}
And here is my Middleware class:
namespace App\Http\Middleware;
use Closure;
class Localize
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param integer $localeUriSegment
* #return mixed
*/
public function handle($request, Closure $next, $localeUriSegment = 1)
{
$locale = $request->segment($localeUriSegment);
if (in_array($locale, config('app.supported_locales')))
{
app()->setLocale($locale);
}
else
{
abort(500, "Locale `{$locale}` in URL `".$request->url().'` is not supported.');
}
return $next($request);
}
}
Hope that helps :)
I have a problem with a zend2 form. I made an entity which gets some data from the database and joins some tables...
here is the entity:
class Campaigns
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
protected $id;
/**
*
* #ORM\Column(name="campaign_name", type="string")
*
*/
protected $campaigns;
/**
* #var mixed
*
* #ORM\ManyToMany(targetEntity="Application\Entity\Countries", cascade={"persist"}, orphanRemoval=false)
* #ORM\JoinTable(name="campaigns_countries",
* joinColumns={#ORM\JoinColumn(name="campaign_id", referencedColumnName="id", onDelete="CASCADE")},
* inverseJoinColumns={#ORM\JoinColumn(name="country_id", referencedColumnName="id", onDelete="CASCADE")}
* )
*/
protected $countries;
Below this code are the getters and setters, a construct function, an add and an remove function.
Here they are:
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
return $this;
}
public function getCampaigns()
{
return $this->campaigns;
}
public function setCampaigns($campaigns)
{
$this->campaigns = $campaigns;
return $this;
}
public function addCampaigns($campaigns = null)
{
foreach ($campaigns as $c) {
if (!$this->campaigns->contains($c)) {
$this->campaigns->add($c);
}
}
}
public function removeCampaigns($campaigns)
{
foreach ($campaigns as $c) {
if ($this->campaigns->contains($c)) {
$this->campaigns->removeElement($c);
}
}
}
public function getCountries()
{
return $this->countries;
}
public function setCountries($countries)
{
$this->countries = $countries;
return $this;
}
public function addCountries($countries = null)
{
foreach ($countries as $c) {
if (!$this->countries->contains($c)) {
$this->countries->add($c);
}
}
}
public function removeCountries($countries)
{
foreach ($countries as $c) {
if ($this->countries->contains($c)) {
$this->countries->removeElement($c);
}
}
} //construct for countries
public function __construct()
{
$this->setCountries(new ArrayCollection());
}
My problem is with the protected $countries. If i add in the form the property value, it gives me the "countries" property not found in entity.
If I do not add it, and instead use __toString() function, it gives me an error saying that it could not convert countries to string...in the __toString() function I added the following code:
public function __toString()
{
return $this->countries;
}
Thank you for all your help!
AE
You say you want a string containing all related countries. The following code demonstrates how you could achieve this:
$campaignCountryNames = array();
$campaignCountries = $campaign->getCountries();
foreach ($campaignCountries as $country) {
// I assume your Country entity has a name property
$campaignCountryNames[] = $country->getName();
}
echo implode(', ', $campaignCountryNames);