This isn't a real fluent interface. I have an object which builds up a method stack. Which gets executed by a single function call. But now I might add another virtual method, which "takes over" that method stack.
Use case: I'm wrapping my superglobals into objects. This allows me to "enforce" input filtering. $_GET and co provide simple sanitizing methods. And my new version now allows chaining of atomic filters. As example:
$_GET->ascii->nocontrol->text["field"]
This is a method call. It uses angle brackets. But that's just a nice trick which eases rewriting any occourence of $_GET["field"]. Anyway.
Now there are also occasionally forms with enumerated fields, as in field[0],field[1],field[2]. That's why I've added a virtual ->array filter method. It hijacks the collected method stack, and iterates the remaining filters on e.g. a $_POST array value. For example $_POST->array->int["list"].
Somewhat shortened implementation:
function exec_chain ($data) {
...
while ($filtername = array_pop($this->__filter)) {
...
$data = $this->{"_$filtername"} ($data);
...
}
function _array($data) {
list($multiplex, $this->__filter) = array($this->__filter, array());
$data = (array) $data;
foreach (array_keys($data) as $i) {
$this->__filter = $multiplex;
$data[$i] = $this->exec_chain($data[$i]);
}
return $data;
}
The method stack gets assembled in the $this->__filter list. Above exec_chain() just loops over it, each time removing the first method name. The virtual _array handler is usually the first method. And it simply steals that method stack, and reexecutes the remainder on each array element. Not exactly like in above example code, but it just repeatedly repopulates the original method stack.
It works. But it feels kind of unclean. And I'm thinking of adding another virtual method ->xor. (YAGNI?) Which would not just iterate over fields, but rather evaluate if alternate filters were successful. For example $_REQUEST->array->xor->email->url["fields"]. And I'm wondering if there is a better pattern for hijacking a function list. My current hook list ($this->__filter) swapping doesn't lend itself to chaining. Hmm well actually, the ->xor example wouldn't need to iterate / behave exactly like ->array.
So specifically, I'm interested in finding an alternative to my $this->__filter list usage with array_pop() and the sneaky swapping it out. This is bad. Is there a better implementation scheme to executing a method list half part me -> half part you?
I've made a similar chaining interface before, I like your idea of using it on GET/POST vars.
I think you will be better off doing something like $var->array->email_XOR_url; rather than $var->array->email->XOR->url;. That way you can catch the various combinations with your __get/__call magic.
Related
please can anyone help me understand what a macro is in Laravel Macroable trait, reading this documentation https://laravel.com/api/5.4/Illuminate/Support/Traits/Macroable.html only tells me how to use but why do I use it, what is it meant for.
It is for adding functionality to a class dynamically at run time.
use Illuminate\Support\Collection;
Collection::macro('someMethod', function ($arg1 = 1, $arg2 = 1) {
return $this->count() + $arg1 + $arg2;
});
$coll = new Collection([1, 2, 3]);
echo $coll->someMethod(1, 2);
// 6 = 3 + (1 + 2)
echo $coll->someMethod();
// 5 = 3 + (1 + 1)
We have 'macroed' some functionality to the Collection class under the name someMethod. We can now call this method on the Collection class and use its functionality.
We just added a method to the class that didn't exist before without having to touch any source files.
For more detail of what is going on, please check out my article on Macros in Laravel:
asklagbox - blog - Laravel Macros
It allows you to add new functions. One call to ::macro adds one new function. This can be done on those of the internal framework classes which are Macroable.
This action of adding the function to the class is done at run time. Note there was/is an already existing perfectly good name for this action, which isn't the word "macro", which I'll explain at the end of this post.
Q. Why would you do this?
A. If you find yourself juggling with these internal classes, like
request & response, adding a function to them might make your code more
readable.
But as always there is a complexity cost in any
abstraction, so only do it if you feel pain.
This article contains a list of the classes you can add functions to using the static call "::macro"
Try not to swallow the word macro though, if you read that article - if you're like me it will give you big indigestion.
So, let's now add one extra function to an internal framework class. Here is the example I have just implemented:
RedirectResponse::macro('withoutQuery', function() {
return redirect()->to(explode('?', url()->previous())[0]);
});
This enables me in a controller to do this:
redirect()->back()->withoutQuery();
(You can just do back() but I added redirect() to make it clear).
This example is to redirect back and where the previous route was something like:
http://myapp.com/home?something=something-else
this function removes the part after '?', to redirect to simply:
http://myapp.com/home
I did not have to code it this way. Indeed another other way to achieve this is for me to put the following function in the base class which all controllers inherit from (App\Http\Controllers\Controller).
public function redirectBackWithoutQuery()
{
return redirect()->to(explode('?',url()->previous())[0]);
}
That means I can in any controller do this:
return $this->redirectBackWithoutQuery();
So in this case the "macro" lets you pretend that your new function is part of an internal framework class, in this case the Illuminate/RedirectResponse class.
Personally I like you found it hard to grasp "laravel macros". I thought that because of the name they were something mysterious.
The first point is you may not need them often.
The second point is the choice of the name ::macro to mean "add a function to a class"
What is a real macro?
A true macro is a concept unique to Lisp. A macro is like a function but it builds and returns actual code which is then executed. It is possible to write a function in other languages which returns a string which you then execute as if it was code, and that would be pretty much the same thing. However if you think about it you have all of the syntax to deal with when you do that. Lisp code is actually structured in lists. A comparison might be imagine if javascript was all written as actual json. Then you could write javascript, which was json, which returned json, which the macro would then just execute. But lisp is a lot simpler than json in terms of its syntax so it is a lot easier than what you just imagined. So, a true lisp macro is one of the most beautiful and amazing things you can encounter.
So why are these add-a-function things in laravel called macros?
That's unknown to me I'm afraid, you'd have to ask the author, but I asked myself what they really do and is there already a name for that.
Monkey Patches
TL;DR laravel's ::macro could more accurately be described as monkey patch
So if using laravel ::macro calls, I personally decided to create a MonkeyPatchServiceProvider and put them all there, to reduce unnecessary confusion for myself.
I realise the name might sound a bit derogatory, but that's not intended at all.
It's simply because there's already a name for this, and we have so much terminology to deal with why not use an existing name.
When removing an element from a form I would usually use
$this->form->remove('foo');
How would I remove an element from a fieldset? for example my $blocks is a fieldset with multiple elements but this doesn't work to remove unwanted elements
$blocks = $this->form->get('page')->get('blocks');
$blocks->remove('active');
When you remove the Form\Element from within a view it will still be present after the creation of the Form that will be passed to the Controller. I strongly suggest for you to be doing a proper OOP approach to your problem. Mainly there's two solutions for this.
The base is always identical, have a Form\Fieldset that matches your Model / Entity. It can have as many child-fieldsets as you need.
Option 1 - Create different Forms and remove elements
Basically this approach would look something like this:
'EntitySubEditForm' => function ($fem) {
$form = new DefaultForm();
$form->get('fieldset')->remove('foo');
$form->get('fieldset')->remove('bar');
return $form;
}
This will basically function like the approach you went, only at the respective place.
The upside to this approach is that you can render your form using $this->formCollection().
The downside to this approach is that even though you may use caching it simply requires more cache-data (hdd-space). And even though it's cheap by now, no reason to waste it ;)
Option 2 - Just don't validate certain fields
You may choose just to ignore some data passed in your special form.
'EntitySubEditForm' => function($fem) {
$form = new DefaultForm();
$form->setValidationGroup(array(
'id', 'name', 'title',
'etc....'
)); // but NOT 'foo' or 'bar'
return $form;
}
This is the approach I'm going. The reason is that I am caching the created Form-Objects so that Form creation is faster. Setting up a validationGroup then allows me to simply ignore values that are sent having these keys. Remember: unvalidated data is NOT passed from Zend\Form.
The downside to this approach is, that you can't render your form using $this->formCollection(), because the elements are still there and would be rendered. You'd have to manually render respective rows using $this->formRow() or even more manually...
more to read...
You may further be interested in the /docs of DoctrineModule #github because it covers a good use-case and describes well how Zend\Form should be used when Forms for specific actions should have different fields. Iirc it uses Option 1.
I'm curious how plugins work, I just know that instead of changing the code we use plugins, but how do they do their job without changing the code ? and what should a coder consider when coding a new project so it can have plugins ? and thank you very much :D
There are multiple variations on how to implement a plugin system. Wordpress uses a quite common scheme often described as "hooks." I don't know the exact implementation but it basically works like this:
// plugin.php script registers its own callback function
register_plugin("hook_type", "plugin_function_123");
function plugin_function_123($params) { ... }
Where the hook_type is often an action name or something. And when the main application runs through a specific point (or e.g. needs some data processsed) it invokes all registered callback functions:
$output = call_plugins("hook_type", $param1, $param2);
This is often implemented behind the scenes as a simple loop:
foreach ($registered_plugins[$action] as $func) {
$func($param1, $param2, ...); // or call_user_func_
}
Now it depends on the hook/action type what parameters are present, and if any result text is expected. There are also differences in parameter passing (e.g. some callbacks require &$var references). And some plugin systems rely on objects instead (if not as many varying action types exist or more complex structures are to be worked with).
So, I don't come from a huge PHP background—and I was wondering if in well formed code, one should use the 'superglobals' directly, e.g. in the middle of some function say $_SESSION['x'] = 'y'; or if, like I'd normally do with variables, it's better to send them as arguments that can be used from there, e.g:
class Doer {
private $sess;
public function __construct(&$sess) {
$this->sess =& $sess;
}
}
$doer = new Doer($_SESSION);
and then use the Doer->sess version from within Doer and such. (The advantage of this method is that it makes clear that Doer uses $_SESSION.)
What's the accepted PHP design approach for this problem?
I do like to wrap $_SESSION, $_POST, $_GET, and $_COOKIE into OOP structures.
I use this method to centralize code that handles sanitation and validation, all of the necessary isset () checks, nonces, setcookie parameters, etc. It also allows client code to be more readable (and gives me the illusion that it's more maintainable).
It may be difficult to enforce use of this kind of structure, especially if there are multiple coders. With $_GET, $_POST, and $_COOKIE (I believe), your initialization code can copy the data, then destroy the superglobal. Maybe a clever destructor could make this possible with $_SESSION (wipe $_SESSION on load, write it back in the destructor), though I haven't tried.
I don't usually use any of these enforcement techniques, though. After getting used to it, seeing $_SESSION in code outside the session class just looks strange, and I mostly work solo.
EDIT
Here's some sample client code, in case it helps somebody. I'm sure looking at any of the major frameworks would give you better ideas...
$post = Post::load ();
$post->numeric ('member_age');
$post->email ('member_email');
$post->match ('/regex/','member_field');
$post->required ('member_first_name','member_email');
$post->inSet ('member_status',array('unemployed','retired','part-time','full-time'));
$post->money ('member_salary');
$post->register ('member_last_name'); // no specific requirements, but we want access
if ($post->isValid())
{
// do good stuff
$firstName = $post->member_first_name;
}
else
{
// do error stuff
}
Post and its friends all derive from a base class that implements the core validation code, adding their own specific functionality like form tokens, session cookie configuration, whatever.
Internally, the class holds a collection of valid data that's extracted from $_POST as the validation methods are called, then returns them as properties using a magic __get method. Failed fields can't be accessed this way. My validation methods (except required) don't fail on empty fields, and many of them use func_get_args to allow them to operate on multiple fields at once. Some of the methods (like money) automatically translate the data into custom value types.
In the error case, I have a way to transform the data into a format that can be saved in the session and used to pre-populate the form and highlight errors after redirecting to the original form.
One way to improve on this would be to store the validation info in a Form class that's used to render the form and power client-side validation, as well as cleaning the data after submission.
Modifying the contents of the superglobals is considered poor practice. While there's nothing really wrong with it, especially if the code is 100% under your control, it can lead to unexpected side effects, especially when you consider mixed-source code. For instance, if you do something like this:
$_POST['someval'] = mysql_real_escape_string($_POST['someval']);
you might expect that everywhere PHP makes that 'someval' available would also get changed, but this is not the case. The copy in $_REQUEST['someval'] will be unchanged and still the original "unsafe" version. This could lead to an unintentional injection vulnerability if you do all your escaping on $_POST, but a later library uses $_REQUEST and assumes it's been escaped already.
As such, even if you can modify them, it's best to treat the superglobals as read-only. If you have to mess with the values, maintain your own parallel copies and do whatever wrappers/access methods required to maintain that copy.
I know this question is old but I'd like to add an answer.
mario's classes to handle the inputs is awesome.
I much prefer wrapping the superglobals in some way. It can make your code MUCH easier to read and lead to better maintainability.
For example, there is some code at my current job the I hate! The session variables are used so heavily that you can't realistically change the implementation without drastically affecting the whole site.
For example,
Let's say you created a Session class specific to your application.
class Session
{
//some nice code
}
You could write something like the following
$session = new Session();
if( $session->isLoggedIn() )
{
//do some stuff
}
As opposed to this
if( $_SESSION['logged'] == true )
{
//do some stuff
}
This seems a little trivial but it's a big deal to me. Say that sometime in the future I decide that I want to change the name of the index from 'logged' to 'loggedIn'.
I now have to go to every place in the app that the session variable is used to change this. Or, I can leave it and find someway to maintain both variables.
Or what if I want to check that that user is an admin user and is logged in? I might end up checking two different variables in the session for this. But, instead I could encapsulate it into one method and shorten my code.
This helps other programmers looking at your code because it becomes easier to read and they don't have to 'think' about it as much when they look at the code. They can go to the method and see that there is only ONE way to have a logged in user. It helps you too because if you wanted to make the 'logged' in check more complex you only have to go to one place to change it instead of trying to do global finds with your IDE and trying to change it that way.
Again, this is a trivial example but depending on how you use the session this route of using methods and classes to protect access could make your life much easier to live.
I would not recommend at all passing superglobal by reference. In your class, it's unclear that what you are modifying is a session variable. Also, keep in mind that $_SESSION is available everywhere outside your class. It's so wrong from a object oriented point of view to be able to modify a variable inside a class from outside that class by modifying a variable that is not related to the class. Having public attribute is consider to be a bad practice, this is even worst.
I found my way here while researching for my new PHP framework.
Validating input is REALLY important. But still, I do often find myself falling back to code like this:
function get( $key, $default=FALSE ){
return (isset($_GET[$key]) ? $_GET[$key]:$default);
}
function post( $key, $default=FALSE ){
return (isset($_POST[$key]) ? $_POST[$key]:$default);
}
function session( $key, $default=FALSE ){
return (isset($_SESSION[$key]) ? $_SESSION[$key]:$default);
}
Which I then use like this:
$page = get('p', 'start');
$first_name = post('first_name');
$last_name = post('last_name');
$age = post('age', -1);
I have found that since I have wildly different requirements for validation for different projects, any class to handle all cases would have to be incredibly large and complex. So instead I write validation code with vanilla PHP.
This is not good use of PHP.
get $_SESSION variables directly:
$id = $_SESSION['id'];
$hash = $_SESSION['hash'];
etc.
im re-factoring php on zend code and all the code is full of $_GET["this"] and $_POST["that"]. I have always used the more phpish $this->_request->getPost('this') and $this->_request->getQuery('that') (this one being not so much logical with the getquery insteado of getGet).
So i was wondering if my method was safer/better/easier to mantain. I read in the Zend Framework documentation that you must validate your own input since the request object wont do it.
That leaves me with 2 questions:
What is best of this two? (or if theres another better way)
What is the best practice for validating php input with this methods?
Thanks!
I usually use $this->_request->getParams(); to retrieve either the post or the URL parameters. Then I use the Zend_Filter_Input to do validation and filtering. The getParams() does not do validation.
Using the Zend_Filter_Input you can do application level validation, using the Zend Validators (or you can write your own too). For example, you can make sure the 'months' field is a number:
$data = $this->_request->getParams();
$validators = array(
'month' => 'Digits',
);
$input = new Zend_Filter_Input($filters, $validators, $data);
Extending Brian's answer.
As you noted you can also check out $this->_request->getPost() and $this->_request->getQuery(). If you generalize on getParams(), it's sort of like using the $_REQUEST superglobal and I don't think that's acceptable in terms of security.
Additional to Zend_Filter, you may also use simple PHP to cast the required.
E.g.:
$id = (int) $this->_request->getQuery('id');
For other values, it gets more complicated, so make sure to e.g. quote in your DB queries (Zend_Db, see quoting identifiers, $db->quoteIdentifier()) and in views use $this->escape($var); to escape content.
You can't write a one-size-fits-all validation function for get/post data. As in some cases you require a field to be a integer and in others a date for instance. That's why there is no input validation in the zend framework.
You will have to write the validation code at the place where you need it. You can of course write some helper methods, but you can't expect the getPost() to validate something for you all by itself...
And it isn't even getPost/getQuery's place to validate anything, it's job is to get you the data you wan't, what happens to it from there on should not be it's concern.
$dataGet = $this->getRequest()->getParam('id',null);
$valid = new Zend_Validate_Digits();
if( isset($dataGet) && $valid->isValid($dataGet) ){
// do some...
} else{
// not set
}
I have always used the more phpish $this->_request->getPost('this') and $this->_request->getQuery('that') (this one being not so much logical with the getquery insteado of getGet).
What is best of this two? (or if theres another better way)
Just a quick explanation on the choice of getQuery(). The wording choice comes from what kind of data it is, not how it got there. GET and POST are just request methods, carrying all sorts of information, including, in the case of a POST request, a section known as "post data". A GET request has no such block, any variable data it carries is part of the query string of the url (the part after the ?).
So, while getPost() gets the data from the post data section of a POST request, getQuery() retrieves data from the query string of either a GET or POST request (as well as other HTTP Request methods).
(Note that GET Requests should not be used for anything that might produce a side effect, like altering a DB row)
So, in answer to your first question, use the getPost() and getQuery() methods, this way, you can be sure of where the data source (if you don't care, getParams() also works, but may include additional data).
What is the best practice for validating php input with this methods?
The best place to validate input is where you first use it. That is to say, when you pull it from getParams(), getPost(), or getQuery(). This way, your data is always correct for where you need it, and if you pass it off, you know it is safe. Keep in mind, if you pass it to another Controller (or Controller Action), you should probably check it again there, just to be safe. How you do this depends on your application, but it still needs to be checked.
not directly related to the topic, but
to insure that you get an number in your input, one could also use $var+0
(however if $var is a float it stays a float)
you may use in most cases
$id = $this->_request->getQuery('id')+0;