So I've been using the Valitron Library to validate posted forms mostly and have run into some issues.
The constructor accepts the data to be validated and this causes problems when you inject the library as a dependency with Pimple or some other container.
It also causes issues if you want to validate multiple things, as you basically have to instantiate the library every time you want to use it.
Is there some way around this?
Ultimately I would like to be able to define the library as a service and inject it with Pimple like this:
$container['Valitron'] = function(){
return new \Valitron\Validator();
};
Any controller/class that needs to validate something would initialise it in their constructor like this:
public function __construct($valitron)
{
$this->valitron = $valitron;
}
Any time I need to validate something I could say something like:
// First use
$this->valitron->setData($_POST);
$this->valitron->rule('required', 'name')->message('Im required')->label('Name');
$this->valitron->validate();
// Second use
$this->valitron->setData($_GET);
$this->valitron->rule('required', 'test')->message('Im also required')->label('Test');
$this->valitron->validate();
But there doesn't seem to be a setData function, or any way to reset the library between usages.
Question:
How do I use Valitron with Pimple and reuse it for validating multiple things at a time?
Please Note: It must be injected. It also should not need to be initialised before each usage. Please don't tell me I have to extend the library or hack it to make it work properly!
Came across your question when I was searching for the same as you did bit I came also across the following Github issue in Valitron's repo, see https://github.com/vlucas/valitron/issues/108
vlucas wrote: Valitron is currently designed to be a one-use instance, so it could lead to weird things like custom labels and error messages not getting reset between validations (because it was never meant to be used that way).
Related
The issue
I have an unexpected warning from PHPStorm when I try to set a new value in a PHP-DI container.
Given the following code:
function inject(Psr\Container\ContainerInterface $container){
$container->set(RandomClass::class, new RandomClass());
}
$container = new DI\Container(); class is instantiated
inject($container);
The following warning is triggered
Potentially polymorphic call. does not have members in its hierarchy
I understand what the warning means, but I do not see why it pops up, especially since I have not found any occurrences of this situation while looking on Google and SO and the documentation does not mention it.
Is there something I am missing, or is this a "false positive" ?
The set() method is not part of Psr\Container\ContainerInterface.
If you want to use that method, you can't typehint against the interface because your code explicitly needs a PHP-DI instance.
Your code doesn't have to be generic, don't overthink things too much. The PSR is useful mostly for frameworks and libraries (who need to be compatible with multiple containers), not for end-users.
The day you switch container library you will have many more complex things to do than just replacing the set() call.
The reason behind the issue
Given the following code (which is very similar to the one I use)
function inject(Psr\Container\ContainerInterface $container){
$container->set(RandomClass::class, new RandomClass());
}
$container = new DI\Container(); class is instantiated
inject($container);
The $container->set(...) call is going to trigger the following warning
Potentially polymorphic call. does not have members in its hierarchy
This is to be expected as Psr\Container\ContainerInterface only contains definitions for the following methods
get($id)
has($id)
The solution
Two possible solutions for this issue:
Type the methods directly with the container, making sure to not use the FQN of the class but only use Container and "use the namespace", it will make changing to a new container package easier (because this is still the goal behind PSRs, being able to almost hot-swap packages).
Create a custom interface based on Psr\Container\ContainerInterface and add the required methods to it.
Or, eventually, you can try to make PHP-FIG extend the PSR-11 standard to include a standard set($id, $value) method.
Say I use a framework like Slim (PHP) and I have this pretty modern code structure:
$app->post("/", function($request, $response) {
// define the post actions here
});
I could put the anonymous function into a separete class, but is there a way to write a test without loosing this code structure?
Thank you.
there are some ways to test that. Regardless, I would recommend splitting each handler into it's own file (probably even a class, that has an __invoke method). The reason is that this way of defining handlers looks short and crisp now. But once you have more than 10 endpoints it gets really ugly to maintain and you're mixing routing logic together with different handlers.
If this is a very small project and you want to keep that kind of syntax, there are two strategies to test it. But be aware that both of them are going to be a bit more cumbersome than you might like:
Integration Test Style (NOT recommended)
you just call $slim->run() in your tests and check if the output of the handler fits your expectations. Slim offers a nice way to mock a http request as you can find at the bottom of that page. Please be aware that you'll be limited to only check on the data that is returned from your handler. If your handler returns plain HTML, you can only check that the html returned contains the right things.
You could take this a bit further if you used slim's dependency injection feature and provided mocks to it.
Simple Handler Style (recommended)
Alternatively you can also keep your anonymous handler function in the routing but defer the handling of the actual business logic to another class, which you could then test. If your controller is very simple and does nothing but retrieve GET/POST parameters and forward them to a class, then there's not such a lot of testing to it.
Besides this giving you an angle to test, it's also a nicer way to think about seperation of concerns. Your slim handler function will take care of framework and HTTP basics, and you'll have a nice domain class that does not need to bother with this.
$app->post("/register", function() {
$result = (new RegisterUserAction())
->register($_POST["email"], $_POST["password1"], $_POST["password2"]);
// now use $result to render the html page to show to the user
});
If you want to test exactly this anonymous function, you can try to mock an $app variable:
$app = $this->getMockBuilder('app class')->disableOriginalConstructor()
->setMethods(['post'])
->getMock();
$app->method('post')->willReturnCallback(function ($url, $anonymousFunction) {
// do some tests with $anonymousFunction
});
I am quite new to OOP, so this is really a basic OOP question, in the context of a Laravel Controller.
I'm attempting to create a notification system system that creates Notification objects when certain other objects are created, edited, deleted, etc. So, for example, if a User is edited, then I want to generate a Notification regarding this edit. Following this example, I've created UserObserver that calls NotificationController::store() when a User is saved.
class UserObserver extends BaseObserver
{
public function saved($user)
{
$data = [
// omitted from example
];
NotificationController::store($data);
}
}
In order to make this work, I had to make NotificationController::store() static.
class NotificationController extends \BaseController {
public static function store($data)
{
// validation omitted from example
$notification = Notification::create($data);
}
I'm only vaguely familiar with what static means, so there's more than likely something inherently wrong with what I'm doing here, but this seems to get the job done, more or less. However, everything that I've read indicates that static functions are generally bad practice. Is what I'm doing here "wrong," per say? How could I do this better?
I will have several other Observer classes that will need to call this same NotificationController::store(), and I want NotificationController::store() to handle any validation of $data.
I am just starting to learn about unit testing. Would what I've done here make anything difficult with regard to testing?
I've written about statics extensively here: How Not To Kill Your Testability Using Statics. The gist of it as applies to your case is as follows:
Static function calls couple code. It is not possible to substitute static function calls with anything else or to skip those calls, for whatever reason. NotificationController::store() is essentially in the same class of things as substr(). Now, you probably wouldn't want to substitute a call to substr by anything else; but there are a ton of reasons why you may want to substitute NotificationController, now or later.
Unit testing is just one very obvious use case where substitution is very desirable. If you want to test the UserObserver::saved function just by itself, because it contains a complex algorithm which you need to test with all possible inputs to ensure it's working correctly, you cannot decouple that algorithm from the call to NotificationController::store(). And that function in turn probably calls some Model::save() method, which in turn wants to talk to a database. You'd need to set up this whole environment which all this other unrelated code requires (and which may or may not contain bugs of its own), that it essentially is impossible to simply test this one function by itself.
If your code looked more like this:
class UserObserver extends BaseObserver
{
public function saved($user)
{
$data = [
// omitted from example
];
$this->NotificationController->store($data);
}
}
Well, $this->NotificationController is obviously a variable which can be substituted at some point. Most typically this object would be injected at the time you instantiate the class:
new UserObserver($notificationController)
You could simply inject a mock object which allows any methods to be called, but which simply does nothing. Then you could test UserObserver::saved() in isolation and ensure it's actually bug free.
In general, using dependency injected code makes your application more flexible and allows you to take it apart. This is necessary for unit testing, but will also come in handy later in scenarios you can't even imagine right now, but will be stumped by half a year from now as you need to restructure and refactor your application for some new feature you want to implement.
Caveat: I have never written a single line of Laravel code, but as I understand it, it does support some form of dependency injection. If that's actually really the case, you should definitely use that capability. Otherwise be very aware of what parts of your code you're coupling to what other parts and how this will impact your ability to take it apart and refactor later.
I've been working on a project and I decided it'd be a good idea to have some sort of, like, DAO, but simplified.
Basically, the only thing I want from it (right now, at least) is to fetch me objects by model name and id. I wrote this very simple piece of code:
class DAO {
public static function get($className,$id) {
$queryName = $className."Query";
if (!class_exists($className) || !class_exists($queryName)) {
return false;
}
$q = $queryName::create()->filterByID($id)->find();
return $q;
}
}
However, I found myself stuck with the implementation. I guess I need to somehow autoload it so that it'll be able to check for the existence of the classes and so that I could use it anywhere inside my app, but I don't know how. Can anyone help me out? Or if there's a better way to do that, I'll appreciate any input.
What you're looking for is a Service.
Definition from the documentation:
Put simply, a Service is any PHP object that performs some sort of
"global" task. It's a purposefully-generic name used in computer
science to describe an object that's created for a specific purpose
(e.g. delivering emails). Each service is used throughout your
application whenever you need the specific functionality it provides.
Defining your class as a service is as simple as this:
app/config/config.yml
...
services:
my_dao:
class: Your\Bundle\DAO
...
Now you can access DAO in your controllers doing something like this:
$dao = $this->get('my_dao');
When you make this call, the Service Container will create an instance of your class and return it. There will always be at most one instance (singleton) and if it's never called, it won't even be instantiated.
I recommend reading the documentation.
Opinion
It seems like you're having trouble adapting to the Symfony way.
If you take a look at The Book you'll see that the Entity Manager in conjunction with your entity's Repository handle most of what DAO's traditionally did. In other words, there's really no need for your DAO class.
For example, fetching any object by id is as easy as:
$om->getRepository('YourBundle:YourModel')->find($id);
Anyway, if you're particularly fond of that approach, you may want to try this project.
I'm currently creating something based on OOP principles and I'm trying to apply dependency injection. I'm aware that I'm possibly doing something wrong here, the whole DI thing seems to be more confusing that it probably is but I'm still struggling to quite get my head around it.
I've created a Form class which will output various form elements but the form class will need at least two other classes (created as objects) to function properly.
Here's how I've got it:
$config = new Config();
$db = new Database();
$html = new HTML();
$form = new Form($config, $db, $html);
This is just me playing around so Form may not need all of those things but I'm using them to illustrate the point.
Now, when I'm creating a form, I don't want to have to pass the three objects into it to use it. I could solve this with static methods etc but it's really not a path I'm wanting to go down.
So what's the best way to be able to use the three objects created earlier in the Form class?
I guess I'm wanting an almost global type of behavior to a certain extent.
I've found a couple of things talking about this and factories, IoC containers etc but nothing that explained it clearly and easily so any help with this would be great. Or even a link to an easy to understand tutorial or something as I've failed to find one myself.
I also found Pimple - could something like that be along the right lines?
Well, if you don't pass the three objects in, you are not doing dependency injection.
To avoid the parameters again, you can write either a Wrapper class, or a factory class which has methods to create and return a form object. You could initialize rhe factory class with $config, $db, $html once and then use that for every form created.
So the process would look like this:
$factory= new Factory($config, $db, $html);
$form= $factory->createForm();