I have a CMS where users can create and edit their own content in their websites. I also provide the possibility to include forms and galleries by simply replacing specific Div's in their content.
In the past I simply exploded the content on these Div's to an array, replaced the whole Div's with the needed html code (by using PHP's include) to show the form or gallery at that exact position, imploded the whole array to a string again (html) and used in the website.
Now I am trying to achieve the same in Laravel 5:
// example plugins div in HTML
// ******************************
<div class="plugin form"></div>
// PageController.php
// ******************************
$page = Page::where(('url', '=', "home")->first();
$page->text = Helpers::getPlugins($page->text);
// Helpers.php (a non default custom class with functions)
// ******************************
public static function getPlugins($page)
{
$dom = new DOMDocument();
$dom->loadHTML($page, LIBXML_HTML_NOIMPLIED);
$x = $dom->getElementsByTagName("div");
foreach ($x as $node)
{
if (strstr($node->getAttribute('class'), "plugin"))
{
$plugin = explode(" ",$node->getAttribute('class'));
$filename = base_path() . "/resources/views/plugins/" . trim($plugin[1]) . ".blade.php";
if (is_file($filename))
{
ob_start();
include($filename);
ob_get_contents();
$node->nodeValue = ob_get_clean();
}
else
{
$node->nodeValue = "Plugin <strong>".$node->getAttribute('class')."</strong> Not found</div>";
}
}
}
return $dom->saveHTML();
}
Sofar so good, the content is returned but what I get is all the pure text blade markup instead of the Laravel generated html which I want to use.
I think there is a way this could work but I cannot come to think of it.
Try manually building the template by using the method BladeCompiler->compile(), read more here
Edit: I think the facade Blade::compile() will give you access to this function too, just add use Blade at the top of the file.
Related
I would like to add nameddests to locations of an existing PDF which are specified by some string (say: put a nameddest on the first occurence of the string "Chapter 1"). Then I would like to be able to jump to those nameddests using JS events.
What I have achieved so far using PHP and FPDF/FPDI: I can load an existing PDF using FPDI and add nameddests to arbitrary positions using a slightly modified version of [1]. I can then embed the PDF in an iframe and navigate to the nameddests using, for example, JS buttons.
However, so far I need to find out the positions of the nameddests by hand. How can I search the PDF for strings and get the page numbers and positions of the search results such that I can add nameddests there?
[1] http://www.fpdf.org/en/script/script99.php
It is impossible to analyse the content of a PDF document with FPDI.
We (Setasign - author of FPDI and PDF_NamedDestinations) have a product (not free) available which allows you to do handle this task: The SetaPDF-Extractor component.
A simple POC of your project could look like:
<?php
// load and register the autoload function
require_once('library/SetaPDF/Autoload.php');
$writer = new SetaPDF_Core_Writer_Http('result.pdf', true);
$document = SetaPDF_Core_Document::loadByFilename('file/with/chapters.pdf', $writer);
$extractor = new SetaPDF_Extractor($document);
// define the word strategy
$strategy = new SetaPDF_Extractor_Strategy_Word();
$extractor->setStrategy($strategy);
// get the pages helper
$pages = $document->getCatalog()->getPages();
// get access to the named destination tree
$names = $document
->getCatalog()
->getNames()
->getTree(SetaPDF_Core_Document_Catalog_Names::DESTS, true);
for ($pageNo = 1; $pageNo <= $pages->count(); $pageNo++) {
/**
* #var SetaPDF_Extractor_Result_Word[] $words
*/
$words = $extractor->getResultByPageNumber($pageNo);
// iterate over all found words and search for "Chapter" followed by a numeric string...
foreach ($words AS $word) {
$string = $word->getString();
if ($string === 'Chapter') {
$chapter = $word;
continue;
}
if (null === $chapter) {
continue;
}
// is the next word a numeric string
if (is_numeric($word->getString())) {
// get the coordinates of the word
$bounds = $word->getBounds()[0];
// create a destination
$destination = SetaPDF_Core_Document_Destination::createByPageNo(
$document,
$pageNo,
SetaPDF_Core_Document_Destination::FIT_MODE_FIT_BH,
$bounds->getUl()->getY()
);
// create a name (shall be unique)
$name = strtolower($chapter . $word->getString());
try {
// add the named destination to the name tree
$names->add($name, $destination->getPdfValue());
} catch (SetaPDF_Core_DataStructure_Tree_KeyAlreadyExistsException $e) {
// handle this exception
}
}
$chapter = null;
}
}
// save and finish the resulting document
$document->save()->finish();
You can then access the named destinations through the URL this way (the viewer application and browser plugin need to support this):
http://www.example.com/script.php#chapter1
http://www.example.com/script.php#chapter2
http://www.example.com/script.php#chapter10
...
I was wandering if it were possible to store a html schema page with special strings to replace with variable and how to do it.
In an external file, I would like to put the html structure of a product, let's call it schema.php:
<span id="{% id %}">{%= name %}</span>
<span>{%= imageURL() %}</span>
The example above is just a simpler example. In the external file, the html would be more complex. I know that if there were just few lines I could just echo them with a simple function but this is not the case.
In another file I have a class that handle products, let's call it class.php:
class Product {
//logic that is useless to post here.
public function imageURL() {
return "/some/url".$this->id."jpg";
}
}
In this class I would like to add a function that take the content from schema.php and then echo it in the public file for users.
I tried with file_get_contents() and file_put_contents() but it just doesn't work:
$path_to_file = 'data/prodotti/scheda.inc';
$file_contents = file_get_contents($path_to_file);
$file_contents = str_replace(
"{%= ",
"<?php echo $this->",
$file_contents
);
$file_contents = str_replace(
" }",
"; ?>",
$file_contents
);
file_put_contents($path_to_file, $file_contents);
is it possible to call schema.php page and print it with custom variables?
By "schema page" I think you mean "template" and yes, but the best way to do it is to use an existing templating engine such as Smarty or a Mustache implementation like https://github.com/bobthecow/mustache.php instead of implementing it yourself because of the risks of XSS, HTML-injection, and how you'll eventually want features like looping and conditionals.
you can do it normaly with php require func. without any strings to replace, if you just want to use that file as "template" then:
in schema.php:
<?php
echo'<span id="'.$id.'">'.$name.'</span>
<span>'.$imageURL.'</span>';
?>
in class.php:
<?php
class Product {
//logic that is useless to post here.
public function imageURL() {
return "/some/url".$this->id."jpg";
}
}
$imageURL = imageURL(); ?>
Index.php or whatever the main page that handles class.php and temp.php(schema)
<?php
//avoid undefined variables on errors
//in case that you don't check for values submitted
$id = 0;
$name = 0;
$imageURL = '';
//set vars values
$id = /*something*/;
$name = /*something 2*/;
$imageURL = /*something3*/;
//all date will be replaced is ready, oky nothing to wait for
require('path/to/schema.php');
Note: If you gets these data from user, then you should validate with if(isset()).
hope that helps,
I'm required to create a simple template engine; I can't use Twig or Smarty, etc. because the designer on the project needs to be able to just copy/paste her HTML into the template with no configuration, muss/fuss, whatever. It's gotta be really easy.
So I created something that will allow her to do just that, by placing her content between {{ CONTENT }} {{ !CONTENT }} tags.
My only problem is that I want to make sure that if she uses multiple spaces in the tags - or NO spaces - it won't break; i.e. {{ CONTENT }} or {{CONTENT}}
What I have below accomplishes this, but I'm afraid it may be overkill. Anybody know a way to simplify this function?
function defineContent($tag, $string) {
$offset = strlen($tag) + 6;
// add a space to our tags if none exist
$string = str_replace('{{'.$tag, '{{ '.$tag, $string);
$string = str_replace($tag.'}}', $tag.' }}', $string);
// strip consecutive spaces
$string = preg_replace('/\s+/', ' ', $string);
// now that extra spaces have been stripped, we're left with this
// {{ CONTENT }} My content goes here {{ !CONTENT }}
// remove the template tags
$return = substr($string, strpos($string, '{{ '.$tag.' }}') + $offset);
$return = substr($return, 0, strpos($return, '{{ !'.$tag.' }}'));
return $return;
}
// here's the string
$string = '{{ CONTENT }} My content goes here {{ !CONTENT }}';
// run it through the function
$content = defineContent('CONTENT', $string);
echo $content;
// gives us this...
My content goes here
EDIT
Ended up creating a repo, for anyone interested.
https://github.com/timgavin/tinyTemplate
I would suggest to take a look at variable extraction into the template scope.
It's a bit easier to maintain and less overhead, than the replace approach and its often easier to use for the designer. In its basic form, its just PHP variables and short tags.
It depends on which side you generate, e.g. a table and its rows (or complete content blocks) - it could be just <?=$table?> ;) Less work for the designer, more work for you. Or just provide a few rendering examples and helpers, because copy/pasting examples should always work, even with an untrained designer.
Template
The template is just HTML mixed with <?=$variable?> - uncluttered.
src/Templates/Article.php
<html>
<body>
<h1><?=$title?></h1>
<div><?=$content?></div>
</body>
</html>
Usage
src/Controller/Article.php
...
// initalize
$view = new View;
// assign
$view->data['title'] = 'The title';
$view->data['content'] = 'The body';
// render
$view->render(dirname(__DIR__) . '/Templates/Article.php');
View / TemplateRenderer
The core function here is render(). The template file is included and the variable extraction happens in a closure to avoid any variable clashes/scope problems.
src/View.php
class View
{
/**
* Set data from controller: $view->data['variable'] = 'value';
* #var array
*/
public $data = [];
/**
* #var sting Path to template file.
*/
function render($template)
{
if (!is_file($template)) {
throw new \RuntimeException('Template not found: ' . $template);
}
// define a closure with a scope for the variable extraction
$result = function($file, array $data = array()) {
ob_start();
extract($data, EXTR_SKIP);
try {
include $file;
} catch (\Exception $e) {
ob_end_clean();
throw $e;
}
return ob_get_clean();
};
// call the closure
echo $result($template, $this->data);
}
}
Answering specifically what you asked:
My only problem is that I want to make sure that if she uses multiple spaces in the tags - or NO spaces - it won't break
What I have below accomplishes this, but I'm afraid it may be overkill. Anybody know a way to simplify this function?
... the only "slow" part of your function is the preg_replace. Use trim instead, for a very slight increase in speed. Otherwise, don't worry about it. There's no magic PHP command to do what you're looking to do.
I have a Book Now button on each page of my website. I would like to know which button is selected and don't really want to add 25+ blocks to the site to add the class manually. I can use Google Analytics if I can make the button unique (add an additional class based on the page URL). But I'm not a coder although I'm familiar with both PHP and jQuery.
Hye Michael, after reading your question i have tested your scenario on my local test drupal site. And it's really easy to achieve it. Here is a piece of PHP code you need to put into your block you created.
<?php
$url = current_path();
$class_from_url = explode("/", $url);
echo "<a href=[link_to_whatever] class='". $class_from_url[0] ."'>[Link Title]</a>";
?>
Make sure your "PHP filter" module is enabled which will allow you to select PHP code from "Text formats" under the block body.
For Drupal 7, the best way to accomplish your goal would be to copy the theme_button() function to your theme's template.php file and add some custom code to check the URL and add the class.
YOURTHEME_button($vars) {
$element = $variables ['element'];
$element ['#attributes']['type'] = 'submit';
element_set_attributes($element, array('id', 'name', 'value'));
$element ['#attributes']['class'][] = 'form-' . $element ['#button_type'];
if (!empty($element ['#attributes']['disabled'])) {
$element ['#attributes']['class'][] = 'form-button-disabled';
}
// Check URL to determine what button class to add
$button_class = null;
$current_path = base_path() . request_path();
switch ($current_path) {
'/form1':
$button_class = 'button-for-form1';
break;
'/form2':
$button_class = 'button-for-form2';
break;
}
if ($button_class !== null) {
$element ['#attributes']['class'][] = $button_class;
}
return '<input' . drupal_attributes($element ['#attributes']) . ' />';
}
Note that this method will add the class only for URLs that you explicitly specify, and it ignores any user-supplied parameters that might be included as part of the URL.
I'm using Symfony and mPDF.
I'm trying to integrate both but am running into some problems.
I need to capture the content of a view but can't see how to do it.
public function executePDF(sfWebRequest $request)
{
$this->object = $this->getRoute()->getObject();
require_once 'mpdf.php';
/* Example code from mPDF site */
$mpdf=new mPDF('win-1252','A4','','',20,15,48,25,10,10);
$mpdf->useOnlyCoreFonts = true; // false is default
$mpdf->SetProtection(array('print'));
$mpdf->SetTitle("Acme Trading Co. - Invoice");
$mpdf->SetAuthor("Acme Trading Co.");
$mpdf->SetWatermarkText("Paid");
$mpdf->showWatermarkText = true;
$mpdf->watermark_font = 'DejaVuSansCondensed';
$mpdf->watermarkTextAlpha = 0.1;
$mpdf->SetDisplayMode('fullpage');
$this->setLayout(false);
$html = $this->getResponse()->getContent();
$mpdf->WriteHTML($html);
$mpdf->Output();
exit;
}
With the above example, $html is returned as an empty string. I have a view template relating to this action (PDFSuccess.php) which accesses the $object and has the HTML that mPDF will use.
Thanks for any help.
As it is just now, when accessing this action it does open a PDF correctly, but there is no content in it.
Thanks
Haven't done this in this specific context but you could try:
$html = $this->getPartial('moduleName/partialName');
... where the template is a partial (_partialName) inside a given module. As it's a partial, there's no need to switch off the layout.
You can also pass variables to it:
$html = $this->getPartial('moduleName/partialName', array('var' => 'something'));
...
If that doesn't work, here's a question relating to email templates that contains an alternative way of doing this (see the accepted answer):
Email body in Symfony 1.4 mailer?