symfony 1.4 - how to reuse validate method across modules - symfony-1.4

I have a quite complex validate method in module1/actions.php called from module1/executeMyAction
I would like to reuse this in module2 rather than duplicate very similar code.
It feels like I should use a component or something like this but I don't need to call validate from a template I need to call it as part of the module1/executeMyAction or module2/executeMyAction so I can then set various variables for the executeMyActionSuccess.php template to handlle.
Can anyone let me know how I should reuse this validation code, I considered moving it into the form class but that just means I can't set the template variiables and it seems like it is breaking the MVC structure a bit so I'm not happy with that.
Would really appreciate any guidance.

If you want to share some parts of code between actions you can create a custom class which will implement some methods you need. You can put the class in the lib directory of either the application or the whole project.
E.g. create a apps/frontend/lib/myUtil.class.php
class myUtil
{
public static function addNumbers($a, $b)
{
return $a + $b;
}
}
Then in your action you can just use:
$sum = myUtil::addNumbers(2, 3);
If your code depends on some other objects it's best if you don't implement static methods but create an object of the class. E.g.
class myUtil
{
protected $request;
public function __construct(sfWebRequest $request)
{
$this->request = $request;
}
public function sumFromRequest()
{
return $this->request->getParameter('a') + $this->request->getParameter('b');
}
}
then in your action
public function executeSomething(sfWebRequest $request)
{
$util = new myUtil($request);
$this->sum = $util->sumFromRequest();
}
If your code is strictly used for validation of form fields you can create a custom validator which can be then used in your form. (which will definitely be the best solution). You can read about creating custom validators in the Symfony docs.

Related

Api-Platform: using PUT for creating resources

I would like to use the PUT method for creating resources. They are identified by an UUID, and since it is possible to create UUIDs on the client side, I would like to enable the following behaviour:
on PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 if this resource exists, update it
on PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 if this resource does not exist, create it
It's possible to achieve this by implementing an ItemDataProviderInterface / RestrictedDataProviderInterface.
However, my resource is actually a subresource, so let's say I want to create a new Book which references an existing Author.
My constructor looks like this:
/**
* Book constructor
*/
public function __construct(Author $author, string $uuid) {
$this->author = $author;
$this->id = $uuid;
}
But I don't know how to access the Author entity (provided in the request body) from my BookItemProvider.
Any ideas?
In API Platform many things that should occur on item creation is based on the kind of request it is. It would be complicated to change.
Here are 2 possibilities to make what you want.
First, you may consider to do a custom route and use your own logic. If you do it you will probably be happy to know that using the option _api_resource_class on your custom route will enable some listeners of APIPlaform and avoid you some work.
The second solution, if you need global behavior for example, is to override API Platform. Your main problem for this is the ReadListener of ApiPlatform that will throw an exception if it can't found your resource. This code may not work but here is the idea of how to override this behavior:
class CustomReadListener
{
private $decoratedListener;
public function __construct($decoratedListener)
{
$this->decoratedListener = $decoratedListener;
}
public function onKernelRequest(GetResponseEvent $event)
{
try {
$this->decoratedListener->onKernelRequest($event);
} catch (NotFoundHttpException $e) {
// Don't forget to throw the exception if the http method isn't PUT
// else you're gonna break the 404 errors
$request = $event->getRequest();
if (Request::METHOD_PUT !== $request->getMethod()) {
throw $e;
}
// 2 solutions here:
// 1st is doing nothing except add the id inside request data
// so the deserializer listener will be able to build your object
// 2nd is to build the object, here is a possible implementation
// The resource class is stored in this property
$resourceClass = $request->attributes->get('_api_resource_class');
// You may want to use a factory? Do your magic.
$request->attributes->set('data', new $resourceClass());
}
}
}
And you need to specify a configuration to declare your class as service decorator:
services:
CustomReadListener:
decorate: api_platform.listener.request.read
arguments:
- "#CustomReadListener.inner"
Hope it helps. :)
More information:
Information about event dispatcher and kernel events: http://symfony.com/doc/current/components/event_dispatcher.html
ApiPlatform custom operation: https://api-platform.com/docs/core/operations#creating-custom-operations-and-controllers
Symfony service decoration: https://symfony.com/doc/current/service_container/service_decoration.html

Symfony2: Testing entity validation constraints

Does anyone have a good way to unit test an entity's validation constraints in Symfony2?
Ideally I want to have access to the Dependency Injection Container within the unit test which would then give me access to the validator service. Once I have the validator service I can run it manually:
$errors = $validator->validate($entity);
I could extend WebTestCase and then create a client to get to the container as per the docs however it doesn't feel right. The WebTestCase and client read in the docs as more of a facility to test actions as a whole and therefore it feels broken to use it to unit test an entity.
So, does anyone know how to either a) get the container or b) create the validator inside a unit test?
Ok since this got two votes I guess other people are interested.
I decided to get my shovel out and was pleasantly surprised (so far anyway) that this wasn't at all difficult to pull off.
I remembered that each Symfony2 component can be used in a stand alone mode and therefore that I could create the validator myself.
Looking at the docs at: https://github.com/symfony/Validator/blob/master/ValidatorFactory.php
I realised that since there was a ValidatorFactory it was trivial to create a validator (especially for validation done by annotations which I am, although if you look at the docblock on the page I linked above you'll also find ways to validate xml and yml).
First:
# Symfony >=2.1
use Symfony\Component\Validator\Validation;
# Symfony <2.1
use Symfony\Component\Validator\ValidatorFactory;
and then:
# Symfony >=2.1
$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
# Symfony <2.1
$validator = ValidatorFactory::buildDefault()->getValidator();
$errors = $validator->validate($entity);
$this->assertEquals(0, count($errors));
I hope this helps anyone else whose conscience wouldn't allow them to just use WebTestCase ;).
We end up rolling your own base test case to access the dependency container from within a test case. Here the class in question:
<?php
namespace Application\AcmeBundle\Tests;
// This assumes that this class file is located at:
// src/Application/AcmeBundle/Tests/ContainerAwareUnitTestCase.php
// with Symfony 2.0 Standard Edition layout. You may need to change it
// to fit your own file system mapping.
require_once __DIR__.'/../../../../app/AppKernel.php';
class ContainerAwareUnitTestCase extends \PHPUnit_Framework_TestCase
{
protected static $kernel;
protected static $container;
public static function setUpBeforeClass()
{
self::$kernel = new \AppKernel('dev', true);
self::$kernel->boot();
self::$container = self::$kernel->getContainer();
}
public function get($serviceId)
{
return self::$kernel->getContainer()->get($serviceId);
}
}
With this base class, you can now do this in your test methods to access the validator service:
$validator = $this->get('validator');
We decided to go with a static function instead of the class constructor but you could easily change the behavior to instantiate the kernel into the constructor directly instead of relying on the static method setUpBeforeClass provided by PHPUnit.
Also, keep in mind that each single test method in you test case won't be isolated fro, each others because the container is shared for the whole test case. Making modification to the container may have impact on you other test method but this should not be the case if you access only the validator service. However, this way, the test cases will run faster because you will not need to instantiate and boot a new kernel for each test methods.
For the sake of reference, we find inspiration for this class from this blog post. It is written in French but I prefer to give credit to whom it belongs :)
Regards,
Matt
I liked Kasheens answer, but it doesn't work for Symfony 2.3 anymore.
There are little changes:
use Symfony\Component\Validator\Validation;
and
$validator = Validation::createValidatorBuilder()->getValidator();
If you want to validate Annotations for instance, use enableAnnotationMapping() like below:
$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
the rest stays the same:
$errors = $validator->validate($entity);
$this->assertEquals(0, count($errors));
With Symfony 2.8, it seems that you can now use the AbstractConstraintValidatorTest class this way :
<?php
namespace AppBundle\Tests\Constraints;
use Symfony\Component\Validator\Tests\Constraints\AbstractConstraintValidatorTest;
use AppBundle\Constraints\MyConstraint;
use AppBundle\Constraints\MyConstraintValidator;
use AppBundle\Entity\MyEntity;
use Symfony\Component\Validator\Validation;
class MyConstraintValidatorTest extends AbstractConstraintValidatorTest
{
protected function getApiVersion()
{
return Validation::API_VERSION_2_5;
}
protected function createValidator()
{
return new MyConstraintValidator();
}
public function testIsValid()
{
$this->validator->validate(null, new MyEntity());
$this->assertNoViolation();
}
public function testNotValid()
{
$this->assertViolationRaised(new MyEntity(), MyConstraint::SOME_ERROR_NAME);
}
}
You have got a good sample with the IpValidatorTest class
The answer in https://stackoverflow.com/a/41884661/4560833 has to be changed a little for Symfony 4:
Use ConstraintValidatorTestCase instead of AbstractConstraintValidatorTest.
Answer (b): Create the Validator inside the Unit Test (Symfony 2.0)
If you built a Constraint and a ConstraintValidator you don't need any DI container at all.
Say for example you want to test the Type constraint from Symfony and it's TypeValidator. You can simply do the following:
use Symfony\Component\Validator\Constraints\TypeValidator;
use Symfony\Component\Validator\Constraints\Type;
class TypeValidatorTest extends \PHPUnit_Framework_TestCase
{
function testIsValid()
{
// The Validator class.
$v = new TypeValidator();
// Call the isValid() method directly and pass a
// configured Type Constraint object (options
// are passed in an associative array).
$this->assertTrue($v->isValid(5, new Type(array('type' => 'integer'))));
$this->assertFalse($v->isValid(5, new Type(array('type' => 'string'))));
}
}
With this you can check every validator you like with any constraint configuration. You neither need the ValidatorFactory nor the Symfony kernel.
Update: As #psylosss pointed out, this doesn't work in Symfony 2.5. Nor does it work in Symfony >= 2.1. The interface from ConstraintValidator got changed: isValid was renamed to validate and doesn't return a boolean anymore. Now you need an ExecutionContextInterface to initialize a ConstraintValidator which itself needs at least a GlobalExecutionContextInterface and a TranslatorInterface... So basically it's not possible anymore without way too much work.
I don't see a problem with the WebTestCase. If you don't want a client, don't create one ;) But using a possibly different service than your actual application will use, that's a potential pit fall. So personally, I've done like this:
class ProductServiceTest extends Symfony\Bundle\FrameworkBundle\Test\WebTestCase
{
/**
* Setup the kernel.
*
* #return null
*/
public function setUp()
{
$kernel = self::getKernelClass();
self::$kernel = new $kernel('dev', true);
self::$kernel->boot();
}
public function testFoo(){
$em = self::$kernel->getContainer()->get('doctrine.orm.entity_manager');
$v = self::$kernel->getContainer()->get('validator');
// ...
}
}
It's less DRY than Matt answer -- as you'll repeat the code (for each test class) and boot the kernel often (for each test method), but it's self-contained and require no extra dependencies, so it depends on your needs. Plus I got rid of the static require.
Also, you're sure to have the same services that your application is using -- not default or mock, as you boot the kernel in the environnement that you wish to test.
If people still read this one in 2023, prefer to inject the ValidatorInterface for Symfony > 3 / 4.
use Symfony\Component\Validator\Validator\ValidatorInterface;
// ...
$this->validator->validate($myEntity);

Creating Type Safe Collections in Flex

I'm trying to create a collection class in Flex that is limited to housing a specific type of data that i am using (an interface). I have chosen not to extend the ArrayCollection class as it's too generic and doesn't really give me the compile time safety that i'm after. In it's simplistic form my collection contains an array and i manage how objects are added and removed, etc.
What i really want to be able to do is use these collections in for each loops. It definitely doesn't seem as straight forward as say c# where you just implement IEnumerable and IEnumerator (or just using the generic Collection). Is there a way to do this in action script and if so any info on how it is achieved?
Cheers
You need to extend the Flash Proxy class. Extending Proxy allows you to alter how 'get' and 'set' work, as well as 'for..in' and 'for..each' loops. You can find more details on the Livedocs.
Here's an example for your issue:
package
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public class EnumerableColl extends Proxy
{
private var _coll:Array;
public function EnumerableColl()
{
super();
_coll = [ 'test1', 'test2', 'test3' ];
}
override flash_proxy function nextNameIndex( index:int ):int
{
if ( index >= _coll.length ) return 0;
return index + 1;
}
override flash_proxy function nextValue( index:int ):*
{
return _coll[ index - 1];
}
}
}
Take a look at Vector<>. That is about as best as you can go for a typed collection in Flex (4 onwards). However, you will need to implement your own class otherwise. One way, it seems, is to use the Iterator Pattern.
Also, take a look at this SO post.

What is the best way to reuse functions in Flex MVC environment?

I am using a Cairngorm MVC architecture for my current project.
I have several commands which use the same type of function that returns a value. I would like to have this function in one place, and reuse it, rather than duplicate the code in each command. What is the best way to do this?
Create a static class or static method in one of your Cairngorm classes.
class MyStatic
{
public static function myFunction(value:String):String
{
return "Returning " + value;
}
}
Then where you want to use your function:
import MyStatic;
var str:String = MyStatic.myFunction("test");
Another option is to create a top level function (a la "trace"). Check out this post I wrote here.
You have lots of options here -- publicly defined functions in your model or controller, such as:
var mySharedFunction:Function = function():void
{
trace("foo");
}
... static methods on new or existing classes, etc. Best practice probably depends on what the function needs to do, though. Can you elaborate?
Create an abstract base class for your commands and add your function in the protected scope. If you need to reuse it anywhere else, refactor it into a public static method on a utility class.

Is it possible to add behavior to a non-dynamic ActionScript 3 class without inheriting the class?

What I'd like to do is something like the following:
FooClass.prototype.method = function():String
{
return "Something";
}
var foo:FooClass = new FooClass();
foo.method();
Which is to say, I'd like to extend a generated class with a single method, not via inheritance but via the prototype.
The class is generated from a WSDL, it's not a dynamic class, and I don't want to touch the generated code because it will be overwritten anyway.
Long story short, I'd like to have the moral equivalent of C# 3:s Extension Methods for AS3.
Edit: I accepted aib's answer, because it fits what I was asking best -- although upon further reflection it doesn't really solve my problem, but that's my fault for asking the wrong question. :) Also, upmods for the good suggestions.
Yes, such a thing is possible.
In fact, your example is very close to the solution.
Try
foo["method"]();
instead of
foo.method();
#Theo: How would you explain the following working in 3.0.0.477 with the default flex-config.xml (<strict>true</strict>) and even a -compiler.strict parameter passed to mxmlc?
Foo.as:
package
{
public class Foo
{
public var foo:String;
public function Foo()
{
foo = "foo!";
}
}
}
footest.as:
package
{
import flash.display.Sprite;
public class footest extends Sprite
{
public function footest()
{
Foo.prototype.method = function():String
{
return "Something";
}
var foo:Foo = new Foo();
trace(foo["method"]());
}
}
}
Note that the OP said inheritance was unacceptable, as was modifying the generated code. (If that weren't the case, adding "dynamic" to the class definition would probably be the easiest solution.)
Depending on how many methods your class has, this may work:
Actual Class:
public class SampleClass
{
public function SampleClass()
{
}
public function method1():void {
Alert.show("Hi");
}
Quick Wrapper:
var actualClass:SampleClass = new SampleClass();
var QuickWrapper:Object = {
ref: actualClass,
method1: function():void {
this.ref.method1();
},
method2: function():void {
Alert.show("Hello!");
}
};
QuickWrapper.method1();
QuickWrapper.method2();
#aib is unfortunately incorrect. Assuming strict mode (the default compiler mode) it is not possible to modify the prototype of non-dynamic class types in ActionScript 3. I'm not even sure that it's possible in non-strict mode.
Is wrapping an option? Basically you create a class that takes one of the objects you get from the web service and just forwards all method calls to that, but also has methods of its own:
public class FooWrapper extends Foo {
private var wrappedFoo : Foo;
public function FooWrapper( foo : Foo ) {
wrappedFoo = foo;
}
override public function methodFromFoo( ) : void {
wrappedFoo.methodFromFoo();
}
override public function anotherMethodFromFoo( ) : void {
wrappedFoo.anotherMethodFromFoo();
}
public function newMethodNotOnFoo( ) : String {
return "Hello world!"
}
}
When you want to work with a Foo, but also have the extra method you need you wrap the Foo instance in a FooWrapper and work with that object instead.
It's not the most convenient solution, there's a lot of typing and if the generated code changes you have to change the FooWrapper class by hand, but unless you can modify the generated code either to include the method you want or to make the class dynamic I don't see how it can be done.
Another solution is to add a step to your build process that modifies the source of the generated classes. I assume that you already have a step that generates the code from a WSDL, so what you could do is to add a step after that that inserts the methods you need.
Monkey patching is an (inelegant) option.
For example, suppose you don't like the fact that Flex 3 SpriteAsset.as returns a default border metrics of [7,7,7,7] (unlike flex 2). To fix this, you can:
Create a copy of SpriteAsset.as and add it to your project at /mx/core/SpriteAsset.as
Edit your local copy to fix any problems you find
Run your ap
Google "flex monkey patch" for more examples and instructions.

Resources