Simple PHP Templating With Looping - php

Hey I wrote a very simple template system for our designers to use. Its uses str_replace under the hood to do its thing.
Its works great! The issue now is i'd like do some looping (foreach) on some data passed.
Here's and example of the template code
$var_c = [
[
"head" => "a",
"body" => "b",
"foot" => "c"
],
[
"head" => "x",
"body" => "y",
"foot" => "z"
]
];
$tpl_vars = [
"__{var_a}__",
"__{var_b}__",
"__{var_c}__"
];
$real_vars = [
$var_a,
$var_b,
$var_c
];
str_replace($tpl_vars, $real_vars, $content_body);
Note $var_c contains an array and i'd like to loop through this array. How do i achieve that.
For structure i was thinking
__startloop__
loop var_c as c
c[head]
c[body]
c[foot]
__endloop__
I cant seem to get my head around how to code this. :)
UPDATE: Twig, smarty and the likes are too big and cumbersome for the work. Its also introduces the learning curve for the designers to adopt a templating language.

See my Text-Template class. It supports conditions (if), loops (for) and filters: https://github.com/dermatthes/text-template
Example template (String in a variable):
Hello {= name},
Your list of Items:
{for curItem in items}
{=#index1}: {= curItem.name}
{/for}
PHP-Code:
<?php
$data = [
"name" => "Some Username",
"items" => [
["name" => "First Item"],
["name" => "Second Item"]
]
];
$tt = new TextTemplate ($templateString);
echo $tt->apply ($data);
This should do the job.

Related

Remove quotation marks from php number

I know this has been asked before, however nothing seems to work
I have following json output:
"coordinates": [
"18.366466",
"29.898110"
]
However, the output I want is:
"coordinates": [
18.366466,
29.898110
]
$coordinates = array($result->lat, $result->lng);
$output[$i++] = array(
"type" => "Feature",
"geometry" => array("type" => "Point",
"coordinates" => $coordinates),
"properties" => array(
"ID" => $result->id,
"icon" => $result->icon,
"tags" => $tagsForJson,
"title" => $result->title,
"description" => $result->description));
Trim, str_replace and all of those functions are not working
Thank you!
What you're looking to do is type-cast this data into an float.
After preparing (trimming, etc) the string with the numbers, you can do something like this:
$coordinates = array((float)$result->lat, (float)$result->lng);
Or to cast the whole array at once, more simply you could utilize array_map and floatval
$coordinates = array_map('floatval', $coordinates);

Convert to Array or Collection or List

I have a big chunk of data in this format:
[
{"date":"2018-11-17"},{"weather":"sunny"},{"Temp":"9"},
{"date":"2014-12-19"},{"Temp":"10"},{"weather":"rainy"},
{"date":"2018-04-10"},{"weather":"cloudy"},{"Temp":"15"},
{"date":"2017-01-28"},{"weather":"sunny"},{"Temp":"12"}
]
Is there any faster and more efficient way to organize and save it the database for future reference? Like making a comparison of the temperature for different days etc. [date,weather,Temp] are supposed to be in one set.
I've tried str_replace() but I'd like to know if there's any better way.
Taking into account your comment, it seems that is an array of objects in which every three objects make a record (that is form of: date, weather & temp) so you can create this setup with the help of collections:
$string = ['your', 'json', 'string'];
$records = collect(json_decode($string))
->chunk(3) // this creates a subset of every three items
->mapSpread(function ($date, $weather, $temp) { // this will map them
return array_merge((array) $date, (array) $weather, (array) $temp);
});
This will give you this output:
dd($records);
=> Illuminate\Support\Collection {#3465
all: [
[
"date" => "2018-11-17",
"weather" => "sunny",
"Temp" => "9",
],
[
"date" => "2014-12-19",
"Temp" => "10",
"weather" => "rainy",
],
[
"date" => "2018-04-10",
"weather" => "cloudy",
"Temp" => "15",
],
[
"date" => "2017-01-28",
"weather" => "sunny",
"Temp" => "12",
],
],
}
PS: To get the array version of this collections just attach ->all() at the end.
You can check in the Collections documentation a good explanation of the chunk() and mapSpread() methods as well of the rest of the available methods.

get child from multidimensional array based on value php

i'm working on a project where i have a structured object like this:
$main_array= [
[
"key"=> "home",
"value":=> "Go Home!"
],
[
"key"=> "business",
"value"=> "Go to Work!"
],
[
"key"=> "other",
"value"=> "Go where you want!"
]
]
i'd like to know if there is a way to retrieve the object based on the "key" parameter.
What i want to do is "extract" the nested array like
$home_array=["key"=> "home","value":=> "Go Home!"]
and so on for "business" and "others".
in javascript, i can use jquery or underscore to get what i want, is there a php method to achieve this, or something to simulate a "where" clause in a multidimensional array/object?
thak you in advance
You can easily convert the array you have to have the 'key' column to be the main index using array_column()...
$main_array= [
[
"key"=> "home",
"value"=> "Go Home!"
],
[
"key"=> "business",
"value"=> "Go to Work!"
],
[
"key"=> "other",
"value"=> "Go where you want!"
]
];
$out = array_column($main_array, null, "key");
print_r($out['business']);
Outputs...
Array
(
[key] => business
[value] => Go to Work!
)
A few possibilities to get a single item matching a specific key:
Iterate the main array and stop when you get to a child that has the proper key:
$object = (function($key) use($main_array) {
foreach ($main_array as $object) {
if ($object['key'] == $key) return $object;
}
})('business');
(This example uses an anonymous function, but you can just use a simple foreach loop and break when you find the key.)
Reindex the main array and look up the child by key:
$indexed = array_column($main_array, null, 'key');
$object = $indexed['business'];
Construct the array using the key as the index to begin with. Using string keys doesn't preclude the array elements being other arrays that can contain multiple values.
$main_array= [
'home' => ["value"=> "Go Home!"],
'business' => ["value"=> "Go to Work!"],
'other' => ["value"=> "Go where you want!"]
];
Methods 2 and 3 require that they key is unique. Method 1 doesn't, but it will just return the first instance it finds.
If you do have multiple instances of a key, you probably want array_filter. This will work more like the "where clause" you referred to.
$key = 'home';
$filtered = array_filter($main_array, function($item) use ($key) {
return $item['key'] == $key;
});
This will return multiple items instead of just one.

Convert PHP to JSON with Nested Array

I have a PHP variable I need to convert to JSON string.
I have following PHP code:
$username="admin";
$password="p4ssword";
$name="Administrator";
$email="myname#smsfree4all.com"
$params=compact('username', 'password','name','email', 'groups');
json_encode($params);
This works fine. But what I am not sure about is how do I encode the properties in PHP with nested key value pairs shown below:
{
"username": "admin",
"password": "p4ssword",
"name": "Administrator",
"email": "admin#example.com",
"properties": {
"property": [
{
"#key": "console.rows_per_page",
"#value": "user-summary=8"
},
{
"#key": "console.order",
"#value": "session-summary=1"
}
]
}
}
What is this with # before key value?
Something like this should do it
$username="admin"; //more variables
$params=compact('username' /* more variables to be compacted here*/);
$params["properties"] = [
"property" => [
[
"#key" => "console.rows_per_page",
"#value"=> "user-summary=8"
],
[
"#key"=> "console.order",
"#value"=> "session-summary=1"
]
]
];
echo json_encode($params);
The manual has more examples you can use
Notice that:
A key~value array is encoded into an object
A regular array (array of arrays here) is encoded into an array
Those are all the rules you need to consider to encode any arbitrary object
Something like this perhaps?
$properties = [
'property' => [
['#key' => 'console.rows_per_page', '#value' => 'user-summary=8'],
['#key' => 'console.order', '#value' => 'session-summary=1']
]
];
It's difficult to tell what you're asking.
You can nest in PHP using simple arrays, very similar to JavaScript objects:
$grandparent = array(
"person1" => array(
"name" => "Jeff",
"children" => array(
array("name" => "Matt"),
array("name" => "Bob")
)
),
"person2" => array(
"name" => "Dillan",
"children" => array()
)
);

Unset object variable's property in a method, affected its value in parent scope?

I made a small library to read database-exported xml file, and output it as an structured associate array. It can also filter the output by table columns.
After I've done the code, when I play with this class I find something weird. unset is acting as if the variable was passed by reference.
I could not spot any possible bugs, so I put up my the particular method where $this->rows is being set, hoping someone could enlight me.
private function populateData($rowLimit)
{
if (!$this->getColumns()) {
throw new ReaderException(__FUNCTION__ . " # Unable to get columns name.");
}
// database->tableName->rows
$rows = $this->getSimpleXmlElement()->children()->children();
if ($this->getFilteredColumns()) {
$toRemoves = array_values(array_diff($this->getColumns(),
$this->getFilteredColumns()));
foreach ($rows as $row) {
foreach ($toRemoves as $toRemove) {
unset($row->{$toRemove});
}
}
}
$rows = $this->simpleXmlToArray($rows)['row'];
if ($rowLimit) {
$limited = [];
for ($i = 0; $i < $rowLimit; $i++) {
$limited[] = $rows[$i];
}
$this->setRows($limited);
} else {
$this->setRows($rows);
}
$structArray = [
'database' => $this->getDatabaseName(),
'table' => $this->getTableName(),
'columns' => !$this->getFilteredColumns() ? $this->getColumns()
: $this->getFilteredColumns(),
'rows' => $this->getRows()
];
$this->setStruct($structArray);
return $this;
}
$xml = new SomeXmlReader($companyTableFilePath);
$xml->get(1);
output:
[
"database" => "myDatabase",
"table" => "companies",
"columns" => [
"id",
"name",
"license_no",
"phone",
"created",
"modified",
],
"rows" => [
[
"id" => "1",
"name" => "SOME COMPANY NAME",
"license_no" => "884652",
"phone" => null,
"created" => "2015-09-25 16:01:57",
"modified" => "2015-09-25 16:01:57",
],
],
]
When I tried to filter off some columns, I do
$xml->setFilteredColumns(['id','name'])->get(1);
it returns the result as expected: the columns have been trimmed.
Output:
[
"database" => "myDatabase",
"table" => "companies",
"columns" => [
"id",
"name",
],
"rows" => [
[
"id" => "1",
"name" => "SOME COMPANY NAME",
],
],
]
However, right after this line, when I test it again with
$xml->setFilteredColumns(['id','name','phone'])->get(1);
on the next line, something went wrong. The output is:
[
"database" => "myDatabase",
"table" => "companies",
"columns" => [
"id",
"name",
"phone",
],
"rows" => [
[
"id" => "1",
"name" => "SOME COMPANY NAME",
],
],
]
After some tracing, I find that $this->getSimpleXmlElement() had been modified by unset. Within this app lifecycle, I can no longer get the complete/original value of $this->getSimpleXmlElement().
Is there a fundamental mistake I've made, or this is a PHP language behaviour?
There is rather a lot of code to follow through here - consider making a more compact example - but it sounds like your misunderstanding is fairly simple.
Objects are never copied when going from one scope to another, because a variable doesn't "contain" an object, it "points at" one (this is not quite the same as pass-by-reference, but the effect is similar in many cases).
So when you run unset($row->{$toRemove});, you are indeed editing the $row object, and by extension the whole SimpleXML document.
If you want a copy of an object to work with, you have to explicitly "clone" it, as discussed in the PHP manual.

Categories