I have a problem which might be simple but I can't figure it out :)
I have a slim 3 / twig app and have made an global variable so I can get the currentUrl in twig.
In a template-file I wan't an if statement checking if the currentUrl contains the string '/forretter' so it only show these products in an for loop.
If I do an simple {{ currentUrl }} it prints the url as expected - but the if statement doesn't seem to accept the currentUrl variable.
I have tried to do an {% set url = currentUrl %} but no luck.
The if statement I am using looks like this {% if '/forretter' in currentUrl %} all other if statements I set up works like a charm.
home someone has an idea about this cause I beginning to get grey hair on my bald head :)
I have now tried Georgy Ivanov answer and tried to match it to my code - and the twig extension works - but the if statement doesn't.
Here is my container code
<?php
use function DI\get;
use Slim\Views\Twig;
use Cart\Basket\Basket;
use Cart\Models\Product;
use Cart\Models\Edit;
use Cart\Models\Order;
use Cart\Models\Customer;
use Cart\Models\Address;
use Cart\Models\Payment;
use Slim\Views\TwigExtension;
use Slim\Views\IsInUrlExtension;
use Interop\Container\ContainerInterface;
use Cart\Support\Storage\SessionStorage;
use Cart\Support\Storage\Contracts\StorageInterface;
use Cart\Validation\Contracts\ValidatorInterface;
use Cart\Validation\Validator;
return [
'router' => get(Slim\Router::class),
ValidatorInterface::class => function (ContainerInterface $c) {
return new Validator;
},
StorageInterface::class => function (ContainerInterface $c) {
return new SessionStorage('cart');
},
Twig::class => function (ContainerInterface $c) {
$twig = new Twig(__DIR__ . '/../resources/views', [
'debug' => true,
'cache' => false,
]);
$basePath = rtrim(str_ireplace('index.php', '', $c->get('request')->getUri()->getBasePath()), '/');
// Add Slim specific extension
$twig->addExtension(new Twig_Extension_Debug());
$twig->addExtension(new TwigExtension(
$c->get('router'), $basePath,
$c->get('request')->getUri()
));
$twig->addExtension(new IsInUrlExtension($c->get('request')->getUri()));
$twig->getEnvironment()->addGlobal('currentUrl',$c->get('request')->getUri());
$twig->getEnvironment()->addGlobal('basket', $c->get(Basket::class));
return $twig;
},
Product::class => function (ContainerInterface $c) {
return new Product;
},
Edit::class => function (ContainerInterface $c) {
return new Edit;
},
Order::class=> function (ContainerInterface $c) {
return new Order;
},
Customer::class=> function (ContainerInterface $c) {
return new Customer;
},
Address::class=> function (ContainerInterface $c) {
return new Address;
},
Payment::class=> function (ContainerInterface $c) {
return new Payment;
},
Basket::class => function (ContainerInterface $c) {
return new Basket(
$c->get(SessionStorage::class),
$c->get(Product::class)
);
}
];
And here is the twig code with the if statement
{% extends 'templates/app.twig' %}
{% block navigation %}
{% include 'templates/partials/navigation.twig' %}
{% endblock %}
{% block content %}
<div class="row p__top">
{% include 'templates/partials/sidebar_left.twig' %}
<section class="col-sm-12 col-md-6">
<div class="product">
{% if is_in_url('/forretter') %}
<div class="row">
<div class="categori__image">
<img class="card-img-top" src="{{site_url}}/images/varmrogetlaks.jpg" alt="Forretter">
</div>
<header class="menu__block">
<h3 class="menu__title">Forretter</h3>
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<div class="card-deck">
{% include 'products/dinertransportable/partials/produkter.twig' %}
</div>
</div>
{% else %}
test2
{{ dump(currentUrl) }}
{% endif %}
</div>
</section>
{% include 'templates/partials/sidebar_right.twig' %}
</div>
{% endblock %}
You could create a Twig extension, something like this:
<?php
class IsInUrlExtension extends \Twig_Extension
{
public function __construct($currentUrl)
{
$this->currentUrl;
}
public function getName()
{
return 'extName';
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('is_in_url', [$this, 'isInUrl']);
];
}
public function isInUrl(string $substr) : bool
{
return strpos($this->currentUrl, $substr) !== false;
}
}
Add this extension when you're registering Twig component in your container:
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('path/to/templates', [
'cache' => 'path/to/cache'
]);
// Instantiate
$basePath = rtrim(str_ireplace('index.php', '', $container['request']->getUri()->getBasePath()), '/');
// Add Slim specific extension
$view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
// Add your extension
$view->addExtension(new IsInUrlExtension($container->get('request')->getUri()));
return $view;
};
Then you could use it within your templates like this:
{% if is_in_url('/forreter') %}
// substring is in current URL
{% endif %}
The benefit of this method is that you don't have to declare global currentUrl variable in your templates, and this strpos logic is not implemented in your templates, or, rather, it is encapsulated in your reusable extension.
Related
Component A (Search)
component class:
namespace App\Http\Livewire\Admin\Shared;
use Livewire\Component;
class Search extends Component
{
public $searchString = '';
public function updated()
{
$this->emitUp('searchForm', $this->searchString);
}
public function searchData()
{
$this->emitUp('searchForm', $this->searchString);
}
public function render()
{
return view('livewire.admin.shared.search');
}
}
component view:
<form wire:submit.prevent='searchData' class="d-none d-sm-inline-block">
<div class="input-group">
<input wire:model.lazy='searchString' id="textSearch" name="textSearch" type="text"
class="form-control bg-white border border-primary small" placeholder="Tìm kiếm...">
<div class="input-group-append">
<button class="btn btn-primary" type="submit">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form>
Component B (List)
component class:
public $searchString = '';
protected $listeners = ['searchForm'];
public function searchForm($searchStringEmit)
{
$this->searchString = $searchStringEmit;
}
public function getListSupplier()
{
$data = Supplier::where('active', true)
->where('name', 'like', '%' . $this->searchString . '%')
->orderByDesc('id')
->paginate(2);
return $data;
}
public function render()
{
return view('livewire.admin.supplier.list', [
'ListSupplier' => $this->getListSupplier()
]);
}
I have problem with blade front-end. After I click button-search, component-search auto change component view show text wire:id<####>, instead of component-search view.
Example image:
enter image description here
It should have been <div wire:id="xxx"> that's how Livewire marks it's components. Make sure you don't have javascript doing some DOM manipulation. Check your template for more information
create component
<?php
namespace App\Http\Livewire\Teacher\Lesson;
use App\Models\Course;
use App\Models\Lesson;
use Illuminate\Support\Facades\Lang;
use Livewire\Component;
use Livewire\WithFileUploads;
class Create extends Component
{
use WithFileUploads;
public $new_row;
public $authUser;
protected $listeners = ['store'];
public function updatedNewRowImage()
{
$this->validate([
'new_row.video' => 'required|file|max:3000|mimes:mp4',
]);
}
public function mount() {
$this->authUser = \Auth::user();
}
public function rules()
{
return [
'new_row.name.ar' => "required|min:3",
'new_row.name.en' => "required|min:3",
'new_row.content.ar' => "required|min:3",
'new_row.content.en' => "required|min:3",
'new_row.course_id' => 'required|exists:courses,id',
'new_row.video' => 'nullable|file',
'new_row.status' => 'required',
'new_row.duration' => 'required|numeric',
];
}
public function store()
{
$this->validate();
$video_name = $this->new_row['video']->store('video/lessons', 'public');
$this->new_row['video'] = basename(parse_url($video_name, PHP_URL_PATH));
$this->new_row['teacher_id'] = $this->authUser['id'];
Lesson::create($this->new_row);
$this->emit('alert', ['type' => 'success', 'message' => Lang::get('message.success_response_message')]);
return redirect()->route('teacher.lessons.index');
}
//
public function render()
{
$courses = Course::all();
return view('livewire.teacher.lesson.create', compact('courses'));
}
}
Lesson Model
<?php
namespace App\Models;
use App\Traits\FilterScopeModelTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Lesson extends Model
{
use HasFactory, FilterScopeModelTrait,HasTranslations;
public $translatable = ['name','content'];
protected $guarded = [];
protected function video(): Attribute
{
return Attribute::make(
get: fn($value) => ($this->attributes['video'] ?? false) ? asset('storage/videos/lessons/' . $this->attributes['video']) : '',
);
}
}
blade file
<div class="form-group col-md-6 mb-2">
<label class="col-sm-6 col-form-label" for="inputAdsVideo">#lang('teacher.video')</label>
<div class="col-sm-10 col-lg-10 col-md-2">
<input type="file" name="new_row.video" wire:model="new_row.video " id="Video"
class="form-control is-invalid"
>
</div>
#error('new_row.video')
<small class=" text text-danger" role="alert">
<strong>{{ $message }}</strong>
</small>
#enderror
</div>
migration
Schema::create('lessons', function (Blueprint $table) {
$table->id();
$table->json('name')->nullable();
$table->json('content')->nullable();
$table->foreignId('teacher_id')->nullable()->constrained();
$table->foreignId('course_id')->nullable()->constrained();
$table->float('duration')->nullable();
$table->text('video')->nullable();
$table->enum('status',['pending','publish']);
$table->timestamps();
});
crude of lessons to insert data in data base
when i try to insert data in data base this me undefined key
of video
pleas help to solve and try to upload video all data uploaded with me except video
I am working on livewire in my project and I encounter a problem.
I have livewire model and blade file as below:
LivewireCounter.php
class LivewireCounter extends Component
{
public $count;
public function render()
{
return view(Constant::LIVEWIRE_COUNTER_BLADE);
}
public function mount($count = 0)
{
$this->count = $count + 1;
}
public function increment()
{
if($this->count >= Constant::LIVEWIRE_COUNTER_MAX)
{
$this->count = Constant::LIVEWIRE_COUNTER_MAX;
} else {
$this->count++;
}
}
public function decrement()
{
if($this->count <= Constant::LIVEWIRE_COUNTER_MIN)
{
$this->count = Constant::LIVEWIRE_COUNTER_MIN;
} else {
$this->count--;
}
}
}
livewire-counter.blade.php
<div>
<div class="flex inline-block relative w-64">
<button class="px-1" wire:click="decrement">-</button>
<h1>{{ $count }}</h1>
<button class="px-1" wire:click="increment">+</button>
</div>
</div>
I have a coupon blade file which uses livewire to track the coupon ordered by user.
coupon-show.blade.php
#extends(Constant::LAYOUTS_APP)
#section(Constant::LAYOUTS_CONTENT)
<div class="container">
<div>
<p class="text-4xl text-extrabold text-gray-900">{{ $CouponSetting->name }}</p>
#livewire('livewire-counter', ['count' => 9])
</div>
{{$count}}
</div>
</div>
#endsection
The problem I am having is I am unable to retrieve the $count value in the coupon-show.blade.php file. I thought the public property of the livewire component should be able to be accessed by blade view?
ErrorException
Undefined variable: count (View: /Applications/MAMP/htdocs/XXX/resources/views/layouts/coupons/coupon-show.blade.php)
Any idea why?
I have created a template:
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow: function() {
this.isShowing = !this.isShowing;
setTimeout(() => {
this.toggleShow1();
}, 800);
}
}
<script>
<style>
..
</style>
And in the HTML document i'd like to toggle a heading only when isShowing is set to true:
<div v-if="isShowing">
<div>
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
</div>
</div>
But then i get this error: ReferenceError: isShowing is not defined
Any help would be much appreciated. Thanks!
You're using a data of vue instance outside of itself. isShowing can only be used inside the <template> of the same .vue file.
For example:
<template>
<div>
<div v-if="isShowing">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow: function() {
this.isShowing = !this.isShowing;
setTimeout(() => {
this.toggleShow1();
}, 800);
}
}
<script>
<style>
..
</style>
hope all is well. I am trying to install Opencart (2.0.3) into a subdirectory (Ie. www.website.com/shop/) I want the root URL www.website.com to go to a Login page, where once a user logs in. It will redirect them to the /shop/ portion of the site and allow them to continue their business. I was wondering what the easiest way was to accomplish this. Would I install everything in the root folder, and then modify the .htaccess file along with the config files? Then how would i Make the login files work in the root folder? I tried installing everything first into the subdirectory /shop/... but then I get issues trying to figure out how to get files in the root folder to work.
Thanks in advance!
Yes, need to work with ajax functionality as below. In the index.php insert the following code and replace URL_WITH_SHOP with your urlshop. Then I have taken "shop" as sub-folder installation if it is different then replace "shop" with your sub-folder name:
<script src="shop/catalog/view/javascript/jquery/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="shop/catalog/view/javascript/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<div class="container">
<div class="row">
<div id="content" class="col-sm-12 ">
<div class="row ">
<div class="col-sm-6" style="margin: 0px auto; float: none;">
<div class="well">
<h2>Returning Customer</h2>
<p><strong>I am a returning customer</strong></p>
<form method="post" enctype="multipart/form-data">
<div class="error"></div>
<div class="form-group">
<label class="control-label" for="input-email">E-Mail Address</label>
<input type="text" name="email" value="" placeholder="E-Mail Address" id="input-email" class="form-control" />
</div>
<div class="form-group">
<label class="control-label" for="input-password">Password</label>
<input type="password" name="password" value="" placeholder="Password" id="input-password" class="form-control" />
</div>
<button type="button" id="button-cart" data-loading-text="Checking login" class="btn btn-primary ">Login</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript"><!--
$('#button-cart').on('click', function() {
$.ajax({
url: 'shop/index.php?route=account/loginajax',
type: 'post',
data: $('input[type=\'text\'], input[type=\'password\']'),
dataType: 'json',
beforeSend: function() {
$('#button-cart').button('loading');
},
complete: function() {
$('#button-cart').button('reset');
},
success: function(json) {
$('.alert, .text-danger').remove();
$('.form-group').removeClass('has-error');
if (json['error']) {
$('.error').after('<div class="alert alert-danger has-error">' + json['error'] + '</div>');
}
if (json['success']) {
$('.error').after('<div class="alert alert-success">' + json['success'] + '</div>');
window.location = "URL_WITH_SHOP";
}
}
});
});
//--></script>
Above is the presentation layer, now let's make the logical layer, go to shop/catalog/controller/account and create loginajax.php and paste following code:
<?php
class ControllerAccountLoginAjax extends Controller
{
private $error = array();
public function index()
{
$this->load->model('account/customer');
$json = array();
// Login override for admin users
if (!empty($this->request->get['token'])) {
$this->event->trigger('pre.customer.login');
$this->customer->logout();
$this->cart->clear();
unset($this->session->data['wishlist']);
unset($this->session->data['payment_address']);
unset($this->session->data['payment_method']);
unset($this->session->data['payment_methods']);
unset($this->session->data['shipping_address']);
unset($this->session->data['shipping_method']);
unset($this->session->data['shipping_methods']);
unset($this->session->data['comment']);
unset($this->session->data['order_id']);
unset($this->session->data['coupon']);
unset($this->session->data['reward']);
unset($this->session->data['voucher']);
unset($this->session->data['vouchers']);
$customer_info = $this->model_account_customer->getCustomerByToken($this->request->get['token']);
if ($customer_info && $this->customer->login($customer_info['email'], '', true)) {
// Default Addresses
$this->load->model('account/address');
if ($this->config->get('config_tax_customer') == 'payment') {
$this->session->data['payment_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
if ($this->config->get('config_tax_customer') == 'shipping') {
$this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
$this->event->trigger('post.customer.login');
$this->response->redirect($this->url->link('account/account', '', 'SSL'));
}
}
if ($this->customer->isLogged()) {
$this->response->redirect($this->url->link('account/account', '', 'SSL'));
}
if (!$json) {
$this->load->language('account/login');
$this->document->setTitle($this->language->get('heading_title'));
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$json['success'] = "Successfully logging in! ";
unset($this->session->data['guest']);
// Default Shipping Address
$this->load->model('account/address');
if ($this->config->get('config_tax_customer') == 'payment') {
$this->session->data['payment_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
if ($this->config->get('config_tax_customer') == 'shipping') {
$this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
// Add to activity log
$this->load->model('account/activity');
$activity_data = array(
'customer_id' => $this->customer->getId(),
'name' => $this->customer->getFirstName() . ' ' . $this->customer->getLastName()
);
$this->model_account_activity->addActivity('login', $activity_data);
}
else{
$json['error'] = $this->language->get('error_login');
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_account'),
'href' => $this->url->link('account/account', '', 'SSL')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_login'),
'href' => $this->url->link('account/login', '', 'SSL')
);
$data['heading_title'] = $this->language->get('heading_title');
$data['text_new_customer'] = $this->language->get('text_new_customer');
$data['text_register'] = $this->language->get('text_register');
$data['text_register_account'] = $this->language->get('text_register_account');
$data['text_returning_customer'] = $this->language->get('text_returning_customer');
$data['text_i_am_returning_customer'] = $this->language->get('text_i_am_returning_customer');
$data['text_forgotten'] = $this->language->get('text_forgotten');
$data['entry_email'] = $this->language->get('entry_email');
$data['entry_password'] = $this->language->get('entry_password');
$data['button_continue'] = $this->language->get('button_continue');
$data['button_login'] = $this->language->get('button_login');
if (isset($this->error['warning'])) {
$data['error_warning'] = $this->error['warning'];
} else {
$data['error_warning'] = '';
}
$data['action'] = $this->url->link('account/login', '', 'SSL');
$data['register'] = $this->url->link('account/register', '', 'SSL');
$data['forgotten'] = $this->url->link('account/forgotten', '', 'SSL');
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
} else {
$data['success'] = '';
}
if (isset($this->request->post['email'])) {
$data['email'] = $this->request->post['email'];
} else {
$data['email'] = '';
}
if (isset($this->request->post['password'])) {
$data['password'] = $this->request->post['password'];
} else {
$data['password'] = '';
}
} else {
$json['error'] = $this->language->get('error_login');
}
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
protected function validate() {
$this->event->trigger('pre.customer.login');
// Check how many login attempts have been made.
$login_info = $this->model_account_customer->getLoginAttempts($this->request->post['email']);
if ($login_info && ($login_info['total'] >= $this->config->get('config_login_attempts')) && strtotime('-1 hour') < strtotime($login_info['date_modified'])) {
$this->error['warning'] = $this->language->get('error_attempts');
}
// Check if customer has been approved.
$customer_info = $this->model_account_customer->getCustomerByEmail($this->request->post['email']);
if ($customer_info && !$customer_info['approved']) {
$this->error['warning'] = $this->language->get('error_approved');
}
if (!$this->error) {
if (!$this->customer->login($this->request->post['email'], $this->request->post['password'])) {
$this->error['warning'] = $this->language->get('error_login');
$this->model_account_customer->addLoginAttempt($this->request->post['email']);
} else {
$this->model_account_customer->deleteLoginAttempts($this->request->post['email']);
$this->event->trigger('post.customer.login');
}
}
return !$this->error;
}
}
This will help you.
Download files and folders for above codes
Hope it also help you
If you just want the login page then here is the tricks, create index.php or index.html at root folder then paste the following code and change URL_WITH_SHOP in the code with your url with shop like "http://www.example.com/shop" :
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<div class="container">
<div class="row">
<div id="content" class="col-sm-12 ">
<div class="row ">
<div class="col-sm-6" style="margin: 0px auto; float: none;">
<div class="well">
<h2>Returning Customer</h2>
<p><strong>I am a returning customer</strong></p>
<form action="URL_WITH_SHOP/index.php?route=account/login" method="post" enctype="multipart/form-data">
<div class="form-group">
<label class="control-label" for="input-email">E-Mail Address</label>
<input type="text" name="email" value="" placeholder="E-Mail Address" id="input-email" class="form-control" />
</div>
<div class="form-group">
<label class="control-label" for="input-password">Password</label>
<input type="password" name="password" value="" placeholder="Password" id="input-password" class="form-control" />
</div>
<input type="submit" value="Login" class="btn btn-primary" />
</form>
</div>
</div>
</div>
</div>
</div>
</div>
The issue will be if the customer enters wrong username and password then it redirects to the actual login page.