Twig : Unset element from array - twig

I have an array of elements composed of key => value for example:
arr = { 156 : 'one', 99 : 'tow' }
I want to remove an element from the array depending on the key. Like doing unset() in php ? Is it possible ?

You can also use the filter pipe like this:
{% set arr = arr | filter((v, k) => k != '99') %}

You can extend twig to do this
<?php
class Project_Twig_Extension extends \Twig\Extension\AbstractExtension {
public function getFunctions(){
return [
new \Twig\TwigFunction('unset', [$this, 'unset'], [ 'needs_context' => true, ]),
];
}
/**
* $context is a special array which hold all know variables inside
* If $key is not defined unset the whole variable inside context
* If $key is set test if $context[$variable] is defined if so unset $key inside multidimensional array
**/
public function unset(&$context, $variable, $key = null) {
if ($key === null) unset($context[$variable]);
else{
if (isset($context[$variable])) unset($context[$variable][$key]);
}
}
}
Usage inside twig:
<h1>Unset</h1>
{% set foo = 'bar' %}
{% set bar = { 'foo' : 'bar', } %}
<h2>Before</h2>
<table>
<tr>
<td>foo</td><td>{{ foo | default('not applicable') }}</td>
</tr>
<tr>
<td>bar.foo</td><td>{{ bar.foo | default('not applicable') }}</td>
</tr>
</table>
{% do unset('foo') %}
{% do unset('bar', 'foo') %}
<h2>After</h2>
<table>
<tr>
<td>foo</td><td>{{ foo | default('not applicable') }}</td>
</tr>
<tr>
<td>bar.foo</td><td>{{ bar.foo | default('not applicable') }}</td>
</tr>
</table>
output
Before
|------------------------------|------------------------------|
| foo | bar |
| bar.foo | bar |
|------------------------------|------------------------------|
After
|------------------------------|------------------------------|
| foo | not applicable |
| bar.foo | not applicable |
|------------------------------|------------------------------|

Related

How to show image in Excel file download by Maatwebsite package in Laravel 8 project?

I want to show images from the database in an Excel file downloaded using the Laravel Maatwebsite package.
Controller
$data['company_names'] = Company::where('id', Auth::user()->com_id)
->first(['company_name']);
$data['companies'] = $companies;
$data['users'] = $users;
$data['regions'] = $regions;
$data['roles'] = $roles;
$exl = Excel::download(new EmployeeReportExport($data),
'Employee-Report.xlsx');
ob_end_clean();
return $exl;
Export Code
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;
class EmployeeReportExport implements FromView
{
public function __construct($data)
{
$this->data = $data;
}
public function view(): View
{
return view('back-end.premium.hr-reports.employee-report.employee-bulk-report-excel', [
'data' => $this->data
]);
}
}
Blade
<td>{{ $i++ }}</td>
<td>{{ $usersData->company_assigned_id ?? '' }}</td>
<td>{{ $usersData->first_name . ' ' . $usersData->last_name }}</td>
<td><img src="{{ asset($usersData->profile_photo) ?? '' }}" alt=""></td>
<td>{{ $usersData->email ?? null }}</td>
<td>{{ $usersData->phone }}</td>
But it's not showing in the Excel file; it returns the following error.
file_get_contents(http://127.0.0.1:8000/uploads/profile_photos/1667727818.jpg):
failed to open stream: HTTP request failed!

How to get the SUM of a column based on the common value(id) in other column in octobercms

i get stuck here. Hope someone can help. i have a database that store the purchase done users on any project.
here is my table in twig
<tbody>
{% for paid_log in paid_logs %}
{% paid_log.user_id == user.id and paid_log.status == 2 %}
<tr>
<td>{{paid_log.project.name }}</td>
<td>{{paid_log.amount }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
Results
|Project ID| Purchase Amount|
1 |1000
1 |1010
2 |2111
4 |9954
1 |9871
4 |6121
I want to loop through the database and sum up the purchase amount where the project ID is the same?
Expecting something like this:
Project ID |Purchase Total
1 |11881
2 |2111
4 |16075
While possible, Twig isn't ideal for doing calculations like this. The code gets pretty messy. Instead, I would suggest creating the data structure In the onStart() where you define paid_logs.
Example:
function onStart()
{
// ... define $paid_logs and $user
$data = [];
foreach ($paid_logs as $paid_log) {
if ($paid_log->user_id == $user->id && $paid_log->status == 2) {
if (!isset($data[$paid_log->project_id])) {
$data[$paid_log->project->id] = 0;
}
$data[$paid_log->project->id] += $paid_log->amount;
}
}
$this['data'] = $data;
}
Then, in your Twig you can simplify:
{% for project_id, amount in data %}
{{ project_id }} | {{ amount }}
{% endfor %}

Files with .twig extension don't work

I am new with twig and the problem is that when I want to use .twig files it doesn't work same with .html.twig. But when I switch to .html file is working fine. Where is the problem?
EDIT:
index.php:
<?php
use App\Kernel;
use Symfony\Component\Debug\Debug;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
require __DIR__.'/../vendor/autoload.php';
$loader = new Twig_Loader_Filesystem('../templates');
$twig = new Twig_Environment($loader, array(
'cache' => '../compilation_cache',
));
$collection = new RouteCollection();
$collection->add('index', new Route('/', array(
)));
// Twig
if (!isset($_SERVER['APP_ENV'])) {
if (!class_exists(Dotenv::class)) {
throw new \RuntimeException('APP_ENV environment variable is not
defined. You need to define environment variables for configuration or
add "symfony/dotenv" as a Composer dependency to load variables from a
.env file.');
}
(new Dotenv())->load(__DIR__.'/../.env');
}
$env = $_SERVER['APP_ENV'] ?? 'dev';
$debug = $_SERVER['APP_DEBUG'] ?? ('prod' !== $env);
if ($debug) {
umask(0000);
Debug::enable();
}
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) {
Request::setTrustedProxies(explode(',', $trustedProxies),
Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
Request::setTrustedHosts(explode(',', $trustedHosts));
}
$kernel = new Kernel($env, $debug);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
//Product list TEST TWIG->Delete if not using!
$products = 'products';
$products = array(
array('name' => 'Notebook', 'description' => 'Core i7', 'value' =>
800.00, 'date_register' => '2017-06-22',),
array('name' => 'Mouse', 'description'=> 'Razer', 'value' => 125.00,
'date_register' => '2017-10-25',),
array('name' => 'Keyboard', 'description' => 'Mechanical Keyboard',
'value'=> 250.00, 'date_register' => '2017-06-23',)
);
$template = $twig->load('index.twig');
echo $template->display(array('products' => $products));
index.twig:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Twig Example</title>
</head>
<body>
<table border="1" style="width: 80%;">
<thead>
<tr>
<td>Product</td>
<td>Description</td>
<td>Value</td>
<td>Date</td>
</tr>
</thead>
<tbody>
{% for product in products %}
<tr>
<td>{{ product.name }}</td>
<td>{{ product.description }}</td>
<td>{{ product.value }}</td>
<td>{{ product.date_register|date("m/d/Y") }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
I want to load the array from the index.php file but it throw me error:
Unable to find template "layout.html" (looked into: ../templates) in index.twig at line 1.
I am not using file layout.html anymore the file is deleted. When I refactor index.twig file to index.html it disappears.
EDIT(2):
twig.yaml(/config/packages/twig.yaml):
twig:
paths: ['%kernel.project_dir%/templates']
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'
The problem was in the index.php file. When I commented/deleted part:
if (!isset($_SERVER['APP_ENV'])) {
if (!class_exists(Dotenv::class)) {
throw new \RuntimeException('APP_ENV environment variable is not
defined. You need to define environment variables for configuration or
add "symfony/dotenv" as a Composer dependency to load variables from a
.env file.');
}
(new Dotenv())->load(__DIR__.'/../.env');
}
$env = $_SERVER['APP_ENV'] ?? 'dev';
$debug = $_SERVER['APP_DEBUG'] ?? ('prod' !== $env);
if ($debug) {
umask(0000);
Debug::enable();
}
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) {
Request::setTrustedProxies(explode(',', $trustedProxies),
Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
Request::setTrustedHosts(explode(',', $trustedHosts));
}
$kernel = new Kernel($env, $debug);
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
Everything works fine...

Can I extract an associative array into variables?

Lets say I have an associative array like so:
{% set settings = { 'foo':'bar', 'cat':'mouse', 'apple':'banana' } %}
To use this data I would do the following:
{{ settings.foo }}
{{ settings.cat }}
{{ settings.apple }}
However, I wondered if there is a way to extract the keys to variables, and the values to values? Essentially the same as the PHP Extract function. So I can just do this instead:
{{ foo }}
{{ cat }}
{{ apple }}
My very amateurish attempt to do this started out like this:
{% for key,val in settings %}
{% set key = val %}
{% endfor %}
But obviously that doesn't work (or I wouldn't be here). Is there another approach I could take?
Thanks,
Mark
As most things in Twig this can be done by extending Twig
ProjectTwigExtension.php
class ProjectTwigExtension extends Twig_Extension {
public function getFunctions() {
return array(
new Twig_SimpleFunction('extract', array($this, 'extract'), ['needs_context' => true, ]),
);
}
public function extract(&$context, $value) {
foreach($value as $k => $v) $context[$k] = $v;
}
public function getName() {
return 'ProjectTwigExtension';
}
}
Register class in Twig
$twig = new Twig_Environment($loader);
$twig->addExtension(new ProjectTwigExtension());
template.twig
{{ extract({'foo': 'bar', }) }}
{{ foo }} {# output : bar #}
(sidenote) Seems you can't do this by using a closure (see example below) because the compiler of Twig passes the variables in an array, thus creating a copy
With closure
$twig->addFunction(new Twig_SimpleFunction('extract', function (&$context, $value) {
foreach($value as $k => $v) $context[$k] = $v;
}, ['needs_context' => true, ]));
Compiled result
echo twig_escape_filter($this->env, call_user_func_array($this->env->getFunction('extract')->getCallable(), array($context, array("foo" => "bar", "foobar" => "foo"))), "html", null, true);

Only Display a # of Characters in Twig

I am very unfamiliar with twig. Here's what I have:
{% if wp.get_post_meta(post.ID, '_property_website').0 %}
<tr>
<th>{{ wp.__('Website', 'aviators') }}:</th>
<td>{{ wp.get_post_meta(post.ID, '_property_website').0 }}
</td>
</tr>
{% endif %}
I need to restrict this output to 35 characters without killing the link. It needs to still be active but only display 35 characters, plus ideally it would end with... to designate that the url is cut off but that's a bonus. Can anyone help?
I believe http://twig.sensiolabs.org/doc/filters/slice.html is what you are looking for
EDIT
Just found that Twig has an extension called text it includes the wordwrap filter that is exactly what you're looking for
Link: https://github.com/fabpot/Twig-extensions/blob/master/lib/Twig/Extensions/Extension/Text.php
You can make your own Twig Extension. It's very easy.
First you must create the file with the filter code:
<?php
//Acme/AcmeBundle/Twig/AnExtension.php
namespace Acme\AcmeBundle\Twig;
class AnExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
new \Twig_SimpleFilter('cutText', array($this, 'cutTextFilter'))
);
}
public function cutTextFilter($text, $size = 50)
{
if (strlen($text) > $size)
{
return substr($text, 0, $size) . '...';
}
else
{
return $text;
}
}
public function getName()
{
return 'an_extension';
}
}
Then edit the services.yml file from this bundle, located at: /Acme/AcmeBundle/Resources/config/services.yml and add:
services:
acme.twig.an_extension:
class: Acme\AcmeBundle\Twig\AnExtension
tags:
- { name: twig.extension }
and now you can use the filter in your code:
<a href="http://{{ wp.get_post_meta(post.ID, '_property_website').0 }}">
{{ wp.get_post_meta(post.ID, '_property_website').0 | cutText(30) }}
</a>
More info: http://symfony.com/doc/current/cookbook/templating/twig_extension.html

Resources