Synfony3 Console: Add own helper to HelperSet - symfony

Is there a way to add own helpers to the console HelperSet in Symfony3?
I didn't find any helpful thing in the documentation.

Ok i followed the code and find a simple solution. :)
I just have to add my class that implements the HelperInterface, or extend the abstract Helper class.
$this->getHelperSet()->set(new MyHelper(), 'myhelper');
And myhelper class looks like that:
<?php
namespace MyApp\Helper;
use Symfony\Component\Console\Helper\Helper;
class MyHelper extends Helper
{
/**
* #param $string
* #return string
*/
public function doIt($string) {
return 'this is your '.$string;
}
/**
* Returns the canonical name of this helper.
*
* #return string The canonical name
*/
public function getName() {
return 'myhelper';
}
}
And in my code i can use it like:
$myhelper = $this->helperSet->get('myhelper');
$myString = $myhelper->doIt('hallo');
:)

Related

FOSElasticaBundle and FPNTagBudle index tags

I am using FPNTagBudle for tagging my documents and FOSElasticaBundle for indexing them into elasticsearch index.
With FPNTagBudle to load tags into object you need to use loadTagging method like so:
$tagManager = $this->get('fpn_tag.tag_manager');
$tagManager->loadTagging($object);
When a object is edited from form, I have tags loaded so everything works fine and when object is saved index is build up properly. The problem is when I run fos:elastica:populate command to populate all object the tagging is skipped, becasue tagging is not loaded then.
I tried to hook to PRE_TRANSFORM event and loadTagging there but then it messes with the form, because new tags added from the form are wiped by calling loadTagging the second time.
Is it possible to recognize in PRE_TRANSFORM hook that this is populate command so I could loadTagging only then? Or maybe my problem is more fundamental?
I decided to go with PRE_TRANSFORM event and distinguishing whether it comes from form or populate command with php_sapi_name(). Below whole solution:
Subscriber:
<?php
namespace AppBundle\EventSubscriber;
use FOS\ElasticaBundle\Event\TransformEvent;
use FPN\TagBundle\Entity\TagManager;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class ElasticaTransformSubscriber
* #package AppBundle\EventSubscriber
*/
class ElasticaTransformSubscriber implements EventSubscriberInterface
{
/** #var TagManager */
private $tagManager;
/**
* ElasticaTransformSubscriber constructor.
* #param $tagManager
*/
public function __construct(TagManager $tagManager)
{
$this->tagManager = $tagManager;
}
/**
* #param TransformEvent $event
*/
public function preTransformOperations(TransformEvent $event)
{
if (php_sapi_name() === 'cli') {
$object = $event->getObject();
$this->tagManager->loadTagging($object);
}
}
/**
* #return array
*/
public static function getSubscribedEvents()
{
return array(
TransformEvent::PRE_TRANSFORM => 'preTransformOperations',
);
}
}
Service:
app.subscriber.object_transformer_elastica:
class: AppBundle\EventSubscriber\ElasticaTransformSubscriber
arguments: ["#fpn_tag.tag_manager"]
tags:
- { name: kernel.event_subscriber }

How can I use the IsGranted annotation with a string as subject?

I find it really handy that in Symfony I can use annotations to add extra functionality to my controller methods in a clean way. Like this for example:
/**
* #Route("/{id}")
* #IsGranted("view", subject="product")
* #return Response
*/
public function view(Product $product)
{
dump(compact('product'));
return new Response('It worked!');
}
However, for the create method, I don't have a product instance, so I'd like to use the #IsGranted annotation with as the subject the string "App\Entity\Post". I hoped I could do that like this:
/**
* #Route("/")
* #IsGranted("create", subject=Product::class)
* #return Response
*/
public function create()
{
return new Response('Did it work?');
}
But unfortunately I get the following error: Could not find the subject "App\Entity\Product" for the #IsGranted annotation. Try adding a "$App\Entity\Product" argument to your controller method.
So #IsGranted is still under the impression that it's supposed to look for a method parameter with the name $App\Entity\Product. Is there a way I can use it with just a string literal?
Can't you just omit the subject attribute?
I haven't used the annotation but I know that Symfony auth checker allows to call "isGranted" without a subject.
See example here: https://symfony.com/doc/current/security.html#securing-controllers-and-other-code
This is old post, but this is how you could have accomplished it:
/**
* #Route("/", defaults={"my_variable": "my_string"})
* #IsGranted("MY_VOTER", subject="my_variable")
*/
Another way:
class AnotherController extends AbstractDashboardController
{
public function index(): Response
{
$this->denyAccessUnlessGranted('MY_VOTER', 'my_variable');
//...
}
}
unlike the 'IsGranted' annotation, method 'denyAccessUnlessGranted' takes string easier ;)

Symfony - FOSRestBundle - show selected fields

I'm trying to show only selected fields in my REST action in controller.
I've found one solution - I can set groups in Entities/Models and select this group in annotation above action in my Controller.
But actually i don't want use groups, i want determine which fields i wanna expose.
I see one solution - I can create one group for every field in my Entities/Model. Like this:
class User
{
/**
* #var integer
*
* #Groups({"entity_user_id"})
*/
protected $id;
/**
* #var string
*
* #Groups({"entity_user_firstName"})
*/
protected $firstName;
/**
* #var string
*
* #Groups({"entity_user_lastName"})
*/
protected $lastName;
}
And then i can list fields above controller action.
My questions are:
Can I use better solution for this?
Can I list all groups? Like I can list all routes or all services.
This is mainly about serialization not about fosrestbundle itself.
The right way would be to create your own fieldserialization strategy.
This article got it down really nicely:
http://jolicode.com/blog/how-to-implement-your-own-fields-inclusion-rules-with-jms-serializer
It build a custom exclusion strategy as describeted here:
How do I create a custom exclusion strategy for JMS Serializer that allows me to make run-time decisions about whether to include a particular field?
Example code from first link for reference:
custom FieldExclusion strategy:
namespace Acme\Bundle\ApiBundle\Serializer\Exclusion;
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
use JMS\Serializer\Metadata\ClassMetadata;
use JMS\Serializer\Metadata\PropertyMetadata;
use JMS\Serializer\Context;
class FieldsListExclusionStrategy implements ExclusionStrategyInterface
{
private $fields = array();
public function __construct(array $fields)
{
$this->fields = $fields;
}
/**
* {#inheritDoc}
*/
public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext)
{
return false;
}
/**
* {#inheritDoc}
*/
public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext)
{
if (empty($this->fields)) {
return false;
}
$name = $property->serializedName ?: $property->name;
return !in_array($name, $this->fields);
}
}
Interface
interface ExclusionStrategyInterface
{
public function shouldSkipClass(ClassMetadata $metadata, Context $context);
public function shouldSkipProperty(PropertyMetadata $property, Context $context);
}
usage
in controller or where you need it:
$context = new SerializationContext();
$fieldList = ['id', 'title']; // fields to return
$context->addExclusionStrategy(
new FieldsListExclusionStrategy($fieldList)
);
// serialization
$serializer->serialize(new Pony(), 'json', $context);
You should be also able to mix and match with groups eg. you can also set $content->setGroups(['myGroup']) together with the fieldExclusio

Symfony How to get class annotation routing parameter from action

Have a problem here:
/**
* Deal controller.
*
* #Route("/portfolio/{portfolio_id}/deal")
*/
class DealController extends Controller
{
// … some code here…
/**
* Creates a new Deal entity.
*
* #Route("/", name="mb_deal_create")
* #Method("POST")
* #Template("MBPortfolioBundle:Deal:new.html.twig")
*/
public function createAction(Request $request)
{
}
So this is my question: how to get $portfolio_id route parameter defined in class annotation from within this createAction?
If I'm trying just add this parameter to the parameter list - it's null then:
public function createAction(Request $request, $portfolio_id) // no way
If I'm trying to get it from query parameter bag - it's null then:
public function createAction(Request $request)
{
$portfolio_id = $request->query->get('portfolio_id'); // no way
So what I need to do?
I see you've already found the solution but it doesn't hurt to put here another way to solve it:
$context = new RequestContext();
$context->fromRequest($request);
$portfolio_id = $context->getParameter('portfolio_id');
Edit
Move portfolio_id to actions' annotation
/**
* Deal controller.
*
*/
class DealController extends Controller
{
// … some code here…
/**
* Creates a new Deal entity.
*
* #Route("/portfolio/{portfolio}/deal", name="mb_deal_create")
* #Method("POST")
* #Template("MBPortfolioBundle:Deal:new.html.twig")
*/
public function createAction(Request $request, Portfolio $portfolio)
{
}
Mine solution is right here:
$portfolio_id = $request->attributes->get('_route_params')['portfolio_id'];

optional parameters in routes defined through annotations

is there a more elegant way to define optional parameters in annotated routes then to define 2 annotations?
Here's how I did it:
/**
*
* #Route("/view/{lang}/{file}", name="legacy_translation_view_file")
* #Route("/view/{lang}", name="legacy_translation_view")
* #Template()
*/
public function viewAction($lang,$file=null)
{
...
}
i've seen that the annotation class has a field named "defaults" but am not quiet sure about the syntax
thx
Symfony has a page on #Route:
E.g maybe you can try.
/**
* #Route("/{id}/{lang}/{file}", requirements={"id" = "\d+"}, defaults={"file" = null})
*/
public function showAction($id, $lang, $file)
{
}
If null doesn't work try an empty string.

Resources