PHP Fat Free "set" with Closure - php

Does anyone know how to assign and then use a closure in a model/view using F3::set? Or offer a solution to the following scenario?
I'm using version 1.4.4
Here's what I'm trying to do:
//In Model - Loaded from controller w/ F3::call
F3::set('getPrice', function($tax, $profile){
//return price
});
//In View - Inside an F3:repeat of #products
{#getPrice(#product.tax, #product.profile)}
But closures don't seem to be supported... If I load the model using require/include, define the function w/o F3::set, and enable user defined functions in the view I can make it work. But I was hoping to maintain the level of separation afforded by using F3::call/F3::set.
Thanks!

Maybe not the answer you'd like to hear but: The template engine of F3 is horrible restrictive, so I'd recommend to not use it at all. F3 itself is okay for simple projects and luckily you can choose which components you want to use. Simple PHP templates still beat any template engine and with a little wrapper you can easily access F3 variables in them. Your template then could look like that:
<?= $this->getPrice($this->product->tax, $this->product->profile) ?>
The wrapper just needs to include the template and implement __get and __call appropiately.

Okay, so version 1.4.4 didn't support this, but version 2.0 does. Thanks for the great updates in 2.0! Here's the anonymous function support:
Controller-
F3::set('func',
function($a,$b) {
return $a.', '.$b;
}
);
Template-
{{#func('hello','world')}}
And here's the object support:
$foo=new stdClass;
$foo->phrase='99 bottles of beer';
F3::set('myvar',$foo);
{{#myvar->phrase}}
http://fatfree.sourceforge.net/page/views-templates

Related

What is a macro in laravel Macroable

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.

Use a custom function everywhere in the website

I come from the procedural PHP and am learning OOP with Laravel. What I learned so far is very interesting and will ease my developer's life (it's not my job btw).
So, for all my websites, I am using a slug property for all articles, categories, and so on.
I started to use the "str_slug" provided by Laravel which seems to do the job at 99%. The issue I get is when I have such title (in french): "J'ai mangé une pomme", the slug string I get is: "jai-mange-une-pomme" which, in french, is not correct. I would like "j-ai-mange-une-pomme".
It's not really an issue. I can do:
$slug = str_replace('\'','_',$input['name']);
$slug = str_slug($slug, '-');
It suits me well but I wonder how to use anytime I want to use it. I don't want to write it again and again and again.
In procedural, it's easy, I would write a function, such as thePerfectSlug(){} in a helpers.php file (still an example) and will use an include at the top of my index.php. That would do the job.
But in OOP and especially in Laravel (5.1), how can I do that?
Thanks
You still can achieve it with normal function. Laravel uses his own function which are stored in helpers.php file. You can make your own helpers.php file and add it to your main composer.json file at autoload.files.
If you would like to do it in OOP way, create a trait like App\Traits\Sluggify with your method and use it in any class that needs it.

Dynamically declared fields in Kohana

I’ve been building an application with Kohana 3.3, and recently switched development from Coda 2 — a text editor — to PhpStorm 6 — an IDE.
PhpStorm 6 has been very handy in pointing out potential code smells; it prompted me to move from attaching data to views with the __set($key, $value) magic method to instead using the bind($key, $value) method.
Another thing that PhpStorm 6 is complaining about, is that I’m declaring fields dynamically.
I have subclassed Controller_Template, and I’m attaching my view to my template like this:
public function action_index() {
# Create the view
$view = View::factory('project/list');
# Attach the view to the template
$this->template->content = $view;
}
Apparently, content is declared dynamically. I’ve been checking up the class heirarchy, and I can't find the content property declared anywhere (hence why it’s dynamic, I suppose). Is this a code smell? Is dynamic declaration bad? Can I explicitly declare the content property somewhere?
As it is, the code works. I just want to understand why PhpStorm is giving me a notice, and whether or not I’m going about things the right way.
The advantage and disadvantage of PHP is dynamic typing. Its convenient in some cases, but irritating in another. You shown here irritating example. You know, that the $view is object which inherit from View (for example), so you know which functions you can use. If you don't mess anything, there will be View type object always.
Phpstorm don't have this information and thats why you see warning. He wants you also to be careful with this code but in this case you cannot do nothing. You cannot also cast $view to View like in Java:
$this->template->content = (View)$view; //impossible :(
$view and $this->template->content are dynamic typing variables and you cannot change it. Just take care to not assign another type to your variable and everything should work fine.
I wanted to add some info to the answer Kasyx is giving. Everything he says is correct but there is an alternative to set variables in kohana if you hate dynamic typing or like some clarity in what your views are doing. (Template is just another view ;) )
You can also set variables in views with the set() function (docs) eg:
$view->set('foo', 'my value');

How to auto-instantiate a library in CodeIgniter

I'm using a really basic library in Codeigniter. In order to use it I need to pass in a number of config parameters using a config function. My library currently requires me to instantiate it before I can call the config, i.e., I have to use it as below:
$this->load->library('Library');
$instance = new Library();
$instance->config($configparams);
I'd like to use it like standard CodeIgniter libraries:
$this->load->library('Library');
$this->library->config($configparams);
What do I need to add to the library in order to have it auto-instantiate? The code is as below:
class Library {
function config($configparams){
...
}
}
This is working now. I swear it wasn't working before I posted on SO! Thanks for posts.
Once you load a class
$this->load->library('someclass');
Then when use it, need to use lower case, like this:
$this->someclass->some_function();
Object instances will always be lower case
According to the docs, you should just call it. So:
$this->load->library('Library');
$this->library->config($configparams);
But why not just pass $configparams to the constructor:
$this->load->library('Library', $configparams);
Check out the guide for CodeIgniter -- it's a great resource to learn more about the framework. IMHO, there aren't any good books available on the current version; this is it.
You basically call it like anything else.
$this->load->library('Name of Library')
Read more here: http://www.google.com/url?sa=t&source=web&cd=2&ved=0CCIQFjAB&url=http%3A%2F%2Fcodeigniter.com%2Fuser_guide%2Fgeneral%2Fcreating_libraries.html&ei=tLFUTbz3HI3SsAOYgP2aBg&usg=AFQjCNFo751PYFp5SbqzuZMxGhXwMI8SJA

CakePHP View including other views

I have a CakePHP application that in some moment will show a view with product media (pictures or videos) I want to know if, there is someway to include another view that threats the video or threats the pictures, depending on a flag. I want to use those "small views" to several other purposes, so It should be "like" a cake component, for reutilization.
What you guys suggest to use to be in Cake conventions (and not using a raw include('') command)
In the interest of having the information here in case someone stumbles upon this, it is important to note that the solution varies depending on the CakePHP version.
For CakePHP 1.1
$this->renderElement('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.thtml, where $flag will have the value of whatever you pass to it.
For CakePHP 1.2
$this->element('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.ctp, where $flag will have the value of whatever you pass to it.
In both versions the element will have access to all the data the view has access to + any values you pass to it. Furthermore, as someone pointed out, requestAction() is also an option, but it can take a heavy toll in performance if done without using cache, since it has to go through all the steps a normal action would.
In your controller (in this example the posts controller).
function something() {
return $this->Post->find('all');
}
In your elements directory (app/views/element) create a file called posts.ctp.
In posts.ctp:
$posts = $this->requestAction('posts/something');
foreach($posts as $post):
echo $post['Post']['title'];
endforeach;
Then in your view:
<?php echo $this->element('posts'); ?>
This is mostly taken from the CakePHP book here:
Creating Reusable Elements with requestAction
I do believe that using requestAction is quite expensive, so you will want to look into caching.
Simply use:
<?php include('/<other_view>.ctp'); ?>
in the .ctp your action ends up in.
For example, build an archived function
function archived() {
// do some stuff
// you can even hook the index() function
$myscope = array("archived = 1");
$this->index($myscope);
// coming back, so the archived view will be launched
$this->set("is_archived", true); // e.g. use this in your index.ctp for customization
}
Possibly adjust your index action:
function index($scope = array()) {
// ...
$this->set(items, $this->paginate($scope));
}
Your archive.ctp will be:
<?php include('/index.ctp'); ?>
Ideal reuse of code of controller actions and views.
For CakePHP 2.x
New for Cake 2.x is the abilty to extend a given view. So while elements are great for having little bits of reusable code, extending a view allows you to reuse whole views.
See the manual for more/better information
http://book.cakephp.org/2.0/en/views.html#extending-views
Elements work if you want them to have access to the same data that the calling view has access to.
If you want your embedded view to have access to its own set of data, you might want to use something like requestAction(). This allows you to embed a full-fledged view that would otherwise be stand-alone.
I want to use those "small views" to
several other purposes, so It should
be "like" a cake component, for
reutilization.
This is done with "Helpers", as described here. But I'm not sure that's really what you want. The "Elements" suggestion seems correct too. It heavily depends of what you're trying to accomplish. My two cents...
In CakePHP 3.x you can simple use:
$this->render('view')
This will render the view from the same directory as parent view.

Categories