I was playing around with this very basic class to learn more about regexes. What I wanted to achieve is to grab the content from a testview file, grab the string exactly between {{EACH slides}} and {{#EACH}}. The regex now present in the class did just that, plus the variable name in the opening tag. I then wanted to use that string to loop it with the right variable and put it back in place.
But when I use 2 EACH-loops in my view instead of 1, it fails badly. The preg_replace_callback() will match the first opening-tag, and the last closing-tag of the second loop, and give a string something like this:
"htmlbalalbal {{#EACH}} more htmlblabla {{EACH newsitems}} htmlblalblabla"
From:
<div class="rows-container">
{{each slides}}
<div class="row flex-wrap" data-id="{{id}}">
</div>
{{#each}}
</div>
<div class="rows-container">
{{each blogposts}}
<div class="row flex-wrap" data-id="{{id}}">
</div>
{{#each}}
I've been trying the change the regex for quite some time now, and I'm starting to see more and more logic in it... but I have yet not solved my problem. Is it even possible to go down this path? or do I need another solution for scanning multiple EACH loops in my testfile? I will probably soon be using some framework, but I like doing this stuff when I'm bored during the weekends...
class Aclass{
private $each = '~\{\{each ([^{]*)\}\}([^*]*)\{\{\#each\}\}~i';
private $current_file_content = "";
private $testviews = ['/testview.php'];
private $views;
function __construct($views){
$this->views = $views; //not in use
$this->start();
}
private function start(){
foreach($this->testviews as $file){
$this->current_file_content = file_get_contents(ROOT.$file);
$this->scan_each();
}
}
private function scan_each(){
$result = preg_replace_callback($this->each, [$this, '_each'], $this->current_file_content);
}
private function _each($matches){
foreach($matches as $match){
var_dump(htmlspecialchars($match));
echo '<br><br>';
}
}
Edit:16-5 So, I've been going further.. its working great, but it doesn't cover an each inside another each. It's a situation like this, which I think might be useful in the future:
{{each attributes}}
<label>{title}</label>
<select name="{key}" id="{key}" class="select">
<option value="0" selected>choose an option</option>
{{each values}}
<option value="{id}" {selected}>{title}</option>
{{#each}}
</select>
{{#each}}
I've been wondering if there is a way to cover it in 1 regex, and then if the function that processes the outer each-loop sees another each inside, it will finish that 1 first. I'm totaly willing to build the functions myself, but it would be awesome to get some tips. Would you recommend separating the regex? to find {{each X}} and {{#each}} and fix it another way in php, or fix the answered Regex to be able to handle this?
Your regex can be fixed as
'~{{each\s+([^{}]*)}}(.*?){{#each}}~is'
See the regex demo.
The main point here is that [^*]
you used in your pattern matches any character but *
while you need to match any 0+ characters between one string and the other. It can be achieved with .*?
and s
modifier.
Details:
{{each
- a literal substring\s+
- 1+ whitespaces([^{}]*)
- Group 1: zero or more chars other than {
and }
}}
- a literal }}
substring(.*?)
- Group 2: any 0+ chars, as few as possible (due to the lazy *?
quantifier{{#each}}
- a literal {{#each}}
substring.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With