slimphp / php-view Goto Github PK
View Code? Open in Web Editor NEWA Simple PHP Renderer for Slim 3 & 4 (or any other PSR-7 project)
License: MIT License
A Simple PHP Renderer for Slim 3 & 4 (or any other PSR-7 project)
License: MIT License
Is possible ? https://github.com/bobthecow/mustache.php
If yes, tell me.
From the documentation:
Inside your templates you may use $this to refer to the PhpRenderer object to render sub-templates.
Including sub-templates (with fetch
) when you are using layouts is problematic as sub-template content also includes the surrounding layout. Using a straight php include(template.file)
is an effective workaround.
Not so much a bug but a suggestion...
Slim2's view class had 2 methods available ( and 1 private ) in its view class. One allowed you to return a rendered template as a string, the other does what PHP-View render() effectively does.
// Slim2
public function fetch($template, $data = null) // returns rendered partial as string
public function display($template, $data = null) // outputs to screen
protected function render($template, $data = null) // does the parsing and passes to fetch/display
PHP-View only has one option available
// Slim3
public function render(ResponseInterface $response, $template, array $data = [])
The problem with the new implementation is that I cannot render and store partials as strings to be used in other parts of the app. Before I create my own implementation thats 99% similar, I wanted to chime in to see if this feature would be added to PHP-Views.
For example there is no way for me to do this, load up a few partials "alert_view" and "content_view" and then use an "empty_wrapper"
$view['alert_view'] = $this->view->fetch('modules/alert_view.php', $view);
$view['content_view'] = $this->view->fetch('login_view.php', $view);
$this->view->display('wrappers/wrapper_empty_view.php', $view);
Since making the interface like Slim2 is probably not an option as you are using render() as Slim2 display(). Maybe create a new method named:
getPartial, partial, renderPartial?
that will allow you to get the output of a rendered template as a string.
As it stands right now PHP-View doesn't work because the Composer autoloader doesn't match a PhpRenderer
class name against a PHPRenderer.php
file name.
One of two things needs to happen:
PHPRenderer.php
to PhpRenderer.php
PhpRenderer
to PHPRenderer
Both of these approaches fixed autoloading for me. I suspect the first option would be preferred, but I'd be fine with either one since I'm more concerned about it working than the naming style.
I have tried to execute functions such as Ajax and I send the form by ajax, but it does not allow me to finish executing these functions in order to return a processed data from Viwe
Haven't tested it, but to me it seems as if the render
method work on the input response itself instead of cloning it (as described here).
Response objects are immutable which means that the call to render() won’t update the response object; instead it will return us a new object which is why it needs to be captured like this. This is always true when you operate on the response object.
Fixed in #7
All PRs for this repo should be checked by Travis.
Is this possible?
I have a template in a sub directory (within the template directory) but ?php include('header.phtml'); is not working, neither does it if I put slash / (root?) in front.
With Twig I could do;
{% include('header.php') %}
And that 'just worked' wherever the files was from the root of the template dir down.
thanks,
David,
How would you render sub-templates when working with PHP-View? For example, this simple code is not working ("Content" gets outputted last, after the header/footer templates)
$app->get('/', function (Request $request, Response $response) {
return $this->renderer->render($response, "/pages/main.php");
});
//In main.php
<?php $this->render($response, "/header.php", []); ?>
Content
<?php $this->render($response, "/footer.php", []); ?>
I do understand why it's not working (Only one response object), but not how to fix it in a proper way?
Your namespace is currently renderer
but it should probably be a namespace that you will release other packages in later on like your own name probably Geggleto
.
Also I noticed the code is not PSR2, you might want to change that.
Fixed in #9
Como retornar o header application/json.
Tentei
header('Content-Type: application/json');
$response->withHeader('Content-Type', 'application/json');
Porem sem sucesso
Can you update composer.json for PHP 8? Thanks.
Trailing slash should be optional in constructor
Any idea on a timeline for a new release so I can use the templateExists
function added in #77?
When a non-existent template is requested, PHP-View throws a generic RuntimeException. Is it possible to include some additional info in it (errorcode or something alike) to distinguish between 404 errors and other runtime exceptions?
I created a slim4 action to send more than one email. The two emails get their output from views and sends two separate emails.
The first email is sent ok, But the second one is sent with the body of the first and second (The recipient and subject is correct.)
I have excluded the email library by debugging and tracing the values being received. I can confirm the same response body is being set,
I tried making a copy of $response. That did not change things.
The code below is a summary
public function actionContact(RequestInterface $request, ResponseInterface $response, array $args): ResponseInterface
$form_data = (array)$request->getParsedBody();
$notify_view_ = $this->renderer->render(
$response,
'emails/contactus_notify.php',
['form_data' => $form_data]
);
$notify_message = $response->getBody();
$notify_mail = new Email('[email protected], 'Subject 1', $notify_message)->send();
// Send second email
$thankyou_view_ = $this->renderer->render(
$response,
'emails/contactus_thankyou.php',
['form_data' => $form_data]
);
$thankyou_message = $response->getBody();
$thankyou_mail = new Email('[email protected], 'Subject 2', $thankyou_message)->send();
}
I figured after further debugging that the second getBody() was actually concatenating the results of the two render()s.
I tried resetting the body
$response->getBody()->write('');
but this had no effect. The second email is the concatenation of the two writes by render.
just coding as following:
$name = '<script>alert("1");</script>';
$renderer->render($response, "home.phtml", ['name'] => $name);
Hi!, I am new in PHP and I try to create an API with Slim, but when I try to load a javascript file inside a template by <script src="dist/file.js"></script>
, it launch an error: Uncaught SyntaxError: Unexpected token <
.
My project structure is:
slim-tutorial
├── public
| ├── dist
| | └── learning.js
| └── index.php
├── templates
| └── index.html
├── vendor
├── composer.json
└── composer.lock
My public/index.php
code is:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require __DIR__.'/../vendor/autoload.php';
$app = new \Slim\App(['settings' => $config]);
$container = $app->getContainer();
$container['view'] = new \Slim\Views\PhpRenderer(__DIR__.'/../templates/');
$app->get('/', function(Request $request, Response $response) {
$response = $this->view->render($response, 'index.html');
return $response;
});
$app->run();
?>
My templates/index.html
code is:
<!DOCTYPE html>
<html lang="es">
<head>
<base href="./">
<meta charset="UTF-8">
<title>Document</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<body>
<section id="root"></section>
<script type="text/javascript" src="dist/learning.js"></script>
<!-- <script type="text/javascript">
// With this code it works, but if I use src attribute in script tag, it crash
(function() {
var root = document.getElementById('root');
var chidlInput = document.createElement('input');
chidlInput.setAttribute('id', 'name');
root.appendChild(chidlInput);
})();
</script> -->
</body>
</html>
And my public/dist/learning.js
code is:
(function() {
var root = document.getElementById('root');
var chidlInput = document.createElement('input');
chidlInput.setAttribute('id', 'name');
root.appendChild(chidlInput);
})();
My templates/index.html
and public/dist/learning.js
codes is to test, in my final project I will use Angular 5 to develop front-end.
I checked this tutorial about Angular and Slim but it not works.
I tried with PHP 5.6 and PHP 7.2 but both launch the same error.
To run this project I use php -S localhost:8080 -t public public/index.php
, because I have installed PHP without Apache or Nginx.
I work on Windows 10.
Regards.
How can I include template-specific stylesheet files individually when using a layout (without webpack or asset()
function)?
I have a layout that I include $this->phpRenderer->setLayout('layout.html.php');
in which I link the default css files for the general page structure etc. that should be loaded on every request.
Now there are some styles that are specific to one and only one template. I don't want to include this CSS file every time. Only when this template is rendered. (For e.g. when error-page is rendered, I want that error.css
is loaded, otherwise error.css
should not be linked)
Each template content is added via the $content
var in the layout inside the <body>
-tag and to properly add a CSS file I would need to access the <head>
segment.
In Twig, we can use the handy block css
{% block stylesheets %}
{{ parent() }}
<link href="{{ asset('user/user.css') }}" rel="stylesheet">
{% endblock %}
How would I do this with PHP-View?
Maybe use Javascript to modify the head after the page loaded? Or include the content in a <style></style>
tag?
It would be nice if there was a layout option, to not repeat html tags.
Like this https://github.com/slimphp/PHP-View/pull/15/files
When directly including a file, all scope variables are leaking so in effect it's possible to modify the $response
and $this
variables from within the template.
I think there could be an anonymous function inside the render method with own scope:
$render = function() {
extract(func_get_arg(1));
return include func_get_arg(0);
};
ob_start();
$render($this->templatePath . $template, $data);
$output = ob_get_clean();
hello
the way to pass datas to the view renderer differs when using PHP-View and Twig-View
I think this is not the right way
maybe PhpRenderer should also implement \ArrayAccess like Twig class does
regards
It would be very helpful to have a variable from request ($request->getUri()->getBasePath();) always available on the templates e.g. with a middleware without having to pass the above as parameter to renderer->render on all routes each time (like so):
$app->get(...
...
$args['basepath']=$request->getUri()->getBasePath();
return $this->renderer->render($response, 'test.php', $args);
});
Hello,
I was wondering why the render method has a ResponseInterfaceparameter.
Wouldn't it be better to write to the body inside the route-matching middleware:
$response->getBody()->write(
$this->view->render('someTemplate.phtml', $someData)
);
and have the PhpRenderer just do 1 job: pass data into a template and return the resulting string?
For instance, what if i just need to render a template for an html email?
Doesn't this also violate the SRP? In my opinion a view renderer shouldn't have the responsibility of filling a response.
thanks and kind regards
maks
Hi,
Nice piece of code.
Juste 2 questions :
I think this check is useless :
https://github.com/slimphp/PHP-View/blob/master/src/PhpRenderer.php#L149
Am i missing something ????
2a) Why not use a require instead of an include ? there is already a check if the file exist, so using require() is pretty safe from my point of view.
2b) Are you sure there could have a throw exception/throwable from the extract() function ? are the try/catch really usefull ?
Thank you for your clarifications. Keep up the good work.
How can I make a loop in html to display an array?
Through my API I already have a route that receives parameters and creates users, this works perfectly for me. However, I would like to implement an HTML form for the API to provide API clients, the form must be able to access the method (to the database model), so that from the same form you can create the users.
I already have the simple form in HTML.
The question is: How do I access the slim models, so that, once the values of the form have been obtained, I will be able to send them to the model to create the user.
My route to create users:
$this->post('crear', function ($req, $res, $args) {
$r = CandidatoCrearValidation::validate($req->getParsedBody());
if(!$r->response){
return $res->withHeader('Content-type', 'application/json')
->withStatus(422)
->write(json_encode($r->setResponse(false,"Campos no validados.")));
}else{
return $res->withHeader('Content-type', 'application/json')
->write(
json_encode($this->model->candidato->crear($req->getParsedBody()))
);
}
});
My route to show the form:
$this->get('crear/form', function ($req, $res, $args) {
return $this->renderer->render($res, "form-signin.php", $args);
});
How to reproduce:
$_SESSION['user_id'] = 'some_value';
$phpView = new PhpRenderer("path/to/templates", ["title" => "My App"]);
$phpView->setLayout("layout.php");
//...
$phpview->render($response, "hello.php", ["title" => "Hello - My App", "name" => "John"]);
In hello.php
:
<?php var_dump($_SESSION); // Will not be set ?>
Hello <?=$name?>! Your id is: <?= $_SESSION['user_id'] ?>
In layout.php
:
<?php var_dump($_SESSION); // Will be filled as intended ?>
<html><head><title><?=$title?></title></head><body><?=$content?></body></html>
So, in both hello.php
and layout.php
you will be able to get $title
var. But, in hello.php
global $_SESSION var will be empty.
Expected behavior would be leaving global variables intact.
As far as I can tell, there is no (clean) way to insert a path to a named route, or am I missing something? I have create a workaround which I am happy to contribute, but since I only started using the Slim Framework yesterday I want to make sure I am not missing something.
How to implement php-view in slim 4 using php-di?
Hi,
Is it possible to add layout support ?
Could be very usefull.
Thanks
public function __construct($templatePath, array $attributes = [])
{
$this->setTemplatePath($templatePath);
$this->setAttributes($attributes);
}
Это очень важно для наследования класса, сейчас это бессмысленно, все равно все переписывать
protected function protectedIncludeScope ($template, array $data) {
extract($data, EXTR_SKIP); // fix
include $template;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.