When generating a selectRange in Laravel, is it possible to append or pre-append text to the select options label? Like a % sign for instance, so all the labels will read {number}%.
{!! Form::selectRange('number', 1, 99) !!}
There is no such thing in Laravel Collective core. I have created my own utility class which extends from Laravel Collective form builder.
In your blade, you can simply write:
{!! MyCustomForm::selectRange('number', 1, 99, ' %') !!}
This is my custom class which extends from Laravel Collectives Form builder:
<?php
namespace App\Models\Utilities;
use Collective\Html\FormFacade;
class MyCustomForm extends FormFacade
{
/**
* Create a select range field with appending text.
* This function overrides Laravel Collective Form::selectRange()
* function.
*
* #param string $name
* #param string $begin
* #param string $end
* #param string $appended_text
* #param string $selected
* #param array $options
* #return string
*/
public static function selectRange($name, $begin, $end, $appended_text = null, $selected = null, $options = array()){
$html = parent::selectRange($name, $begin, $end, $selected, $options);
$dom = new \DOMDocument();
$dom->loadHTML($html);
$xpath = new \DOMXPath($dom);
$options = $xpath->query("*/select[#name='" . $name . "']/option");
foreach ($options as $option) {
$option->nodeValue = $option->nodeValue . $appended_text;
}
$html = self::innerHTML($dom->documentElement->firstChild);
return $html;
}
/**
* This function removes HTML DOCTYPE, html tag and body tag from the
* generated DOM HTML.
*
* #param DOMNode $node
* #return string
*/
public static function innerHTML($node){
$doc = new \DOMDocument();
foreach ($node->childNodes as $child)
$doc->appendChild($doc->importNode($child, true));
return $doc->saveHTML();
}
}
Let me know if there is still something vague.
Related
Normally TYPO3 assigns a variable in FrontEnd with the name validationResults and it looks like that.
Then we have to iterate through the Error objects and get a list with all the errors and their messages. But there is no way to take each one individually and assign it on the corresponding field where the error appears.
So the question is, how do i do it?
Best regards,
After some programming and a help from larry-pete (typo3.slack.com) i found a solution.
I created my own ViewHelper and it looks like this:
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['mytag'][] = 'Vendor\\ExtensionName\\ViewHelpers';
Classes/ViewHelpers/Form/ErrorViewHelper.php
namespace Vendor\ExtensionName\ViewHelpers\Form;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
class ErrorViewHelper extends AbstractFormFieldViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
$this->registerArgument('as', 'string', '', false, 'flattenedErrors');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
{
$as = $arguments['as'];
$for = $arguments['for'];
$templateVariableContainer = $renderingContext->getVariableProvider();
$controllerContext = $renderingContext->getcontrollerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null){
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getErrors();
$output = $renderChildrenClosure();
$withKeys = [];
if (empty($output)) {
if ($flattenedErrors) {
foreach ($flattenedErrors as $error) {
$withKeys[$error->getTitle()] = $error;
}
}
}
$templateVariableContainer->add($as, $withKeys);
return $output;
}
}
Form.html
<mytag:form.error as="error" for="error"/>
And this returns:
So now, you can do something like that:
<f:if condition="{offer.firstName}"><span style="display: block">{offer.firstName.message}</span></f:if>
Best regards
I changed your Viewhelper a bit because it didn't worked in my version (typo3 9)
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class ErrorViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$for = $arguments['for'];
$controllerContext = $renderingContext->getControllerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null) {
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getFlattenedErrors();
return $flattenedErrors;
}
}
you can do:
{myExt:error() -> f:variable(name: 'errors')}}
or
{ff:error( for:"user" ) -> f:variable(name: 'errors')}}
I try to override the maxSizeMessage atttribute from File in a Symfony 4.2 project however, it is the default message who is returned by the framework ("The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}").
This is my validator configuration for this FormType :
# config\validator\validator.yaml
App\Application\Form\Command\PropertyPicture\PropertyAddPictureCommand:
properties:
image:
- Image:
maxSize: 10M
maxSizeMessage: "Image size over 10M"
mimeTypes: [image/jpeg, image/png, image/gif, image/bmp]
mimeTypesMessage: "Image extension not valid"
uploadErrorMessage: "An error has been encounted during the process"
[EDIT for Michał Tomczuk commentary (2019/04/08)]
This is the "FormType" object in this project (it is a DDD architecture with POMM) :
class PropertyAddPictureCommand
{
/**
* #var string
*/
public $link;
/**
* #var string
*/
public $filename;
/**
* #var Property
*/
public $property;
/**
* #var string
*/
public $pathname;
/**
* #var string
*/
public $directory;
/**
* #var UploadedFile
*/
public $image;
}
[END EDIT for Michał Tomczuk commentary (2019/04/08)]
[EDIT for Michał Tomczuk commentary (2019/04/09)]
This is the FormType object use (the object get before is the values passed in $options array) in the project :
class CommandType extends AbstractType
{
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'name' => 'command_type',
]);
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
foreach (get_object_vars($options['data']) as $key => $value) {
$builder->add($key);
}
}
}
And this is how I call the form object in the controller :
$uploadedFile = $request->files->get('image');
$propertyId = $property->getIdValue();
$directory = 'group'.DIRECTORY_SEPARATOR.$this->getUser()->getGroupId().DIRECTORY_SEPARATOR.'property'.DIRECTORY_SEPARATOR.$propertyId;
$filename = $propertyId.'-'.uniqid().'.'.$uploadedFile->getClientOriginalExtension();
$command = new PropertyAddPictureCommand();
$command->link = $this->getParameter('amazon_s3.bucket_url').'images/'.$directory.DIRECTORY_SEPARATOR.$filename;
$command->filename = $filename;
$command->property = $property;
$command->pathname = $uploadedFile->getPathname();
$command->directory = $directory;
$form = $this->createForm(CommandType::class, $command, ['data_class' => PropertyAddPictureCommand::class]);
$form->submit($request->request->all() + ['image' => $uploadedFile], false);
if (!$form->isValid()) {
throw new NotValidFormException($form);
}
[END EDIT for Michał Tomczuk commentary (2019/04/09)]
I expected to show "Image size over 10M" message when the image size is over 10M.
I think it is a property path issue.
Your form has a name - command_type, which means that every input name is preceeded with it, so instead of appending image to the request, try appending command_type[image].
I think you could also simply map the image to the command object:
$command->image = $uploadedFile;
In this case you don't need to append the image property to the request.
What is the simple way to share partials between themes. Assets are possible but i am having issue with whole partials. I have a multi-theme site managed/activated by sub-domain policies/logic.
SOLUTIONS
/**
*
* Renders a requested partial in context of this component,
* see Cms\Classes\Controller#renderPartial for usage.
*/
/**
* #param $themeName
* #param $partialName
* #param $data
* #return mixed
* #throws \Cms\Classes\CmsException
*/
public function renderThemePartial($partialName, $themeName, $data)
{
$theme = Theme::getActiveTheme();
if($themeName) {
$theme = Theme::load($themeName);
}
$controller = new Controller($theme);
return $controller->renderPartial($partialName, $data);
}
/**
*
* Renders a requested content in context of this component,
* see Cms\Classes\Controller#renderContent for usage.
*/
/**
* #param $themeName
* #param $contentName
* #param $data
* #return string
* #throws \Cms\Classes\CmsException
*/
public function renderThemeContent($contentName, $themeName, $data)
{
$theme = Theme::getActiveTheme();
if($themeName) {
$theme = Theme::load($themeName);
}
$controller = new Controller($theme);
return $controller->renderContent($contentName, $data);
}
public function registerMarkupTags()
{
return [
'functions' => [
'partial_from_theme' => [$this, 'themePartial'],
'content_from_theme' => [$this, 'themeContent'],
],
'filters' => [
'theme_asset' => [$this, 'themeUrl']
]
];
}
/**
* #param $requested
* #return string
*/
public function themeUrl($requested)
{
$asset = $requested[0];
$theme = $requested[1];
$theme = Theme::load($theme);
$themeDir = $theme->getDirName();
if (is_array($asset)) {
$_url = Url::to(CombineAssets::combine($asset, themes_path().'/'.$themeDir));
}
else {
$_url = Config::get('cms.themesPath', '/themes').'/'.$themeDir;
if ($asset !== null) {
$_url .= '/'.$asset;
}
$_url = Url::asset($_url);
}
return $_url;
}
/**
* #param $partialName
* #param null $themeName
* #param array $parameters
* #return mixed
* #throws \Cms\Classes\CmsException
*/
public function themePartial($partialName, $themeName = null, $parameters = [])
{
return $this->renderThemePartial($partialName, $themeName, $parameters);
}
/**
* #param $contentName
* #param null $themeName
* #param array $parameters
* #return string
* #throws \Cms\Classes\CmsException
*/
public function themeContent($contentName, $themeName = null, $parameters = [])
{
return $this->renderThemeContent($contentName, $themeName, $parameters);
}
I guess you can use Plugin component here you can add component to page and use its partial.
You need to define partial [ you can add as many as you like ] in component.
And just use that partial like below in page , now this same thing you can do in other themes as well.
When you change partial it will affect in all other themes like its shared across multiple themes.
Down side will be that you can not change its content from backend, you need to manually change that file from ftp or other manner.
Partial from another theme
Hmm
you can add custom twig function for that may be
In any of your plugin you can add this code
public function registerMarkupTags()
{
return [
'functions' => [
'theme_partial' => [$this, 'themePartial'],
]
];
}
public function themePartial($partialName, $themeName = null, $vars = [])
{
$theme = Theme::getActiveTheme();
if($themeName) {
$theme = Theme::load($themeName);
}
$template = call_user_func([Partial::class, 'load'], $theme, $partialName);
$partialContent = $template->getTwigContent();
$html = Twig::parse($partialContent, $vars);
return $html;
}
Now inside your theme when you want to use partial you can use
{{ theme_partial('call_from_other_theme', 'stemalo' ,{'name':'hardik'}) }}
^ Your theme name here.
themes/stemalo/partials/call_from_other_theme.htm content
description = "Shared Partial."
[viewBag]
==
<div id="shared_partial">
<h1>Another Theme Partial : {{name}}</h1>
</div>
this way you can use partial from another themes.
you aksed for access to theme directory here may be you can just you need to pass theme name, and `its dynamic you can pass variable as theme name so it can pick any thing you like.
If any doubt please comment.
i have address Book table and user table i am assigning
the many user in my address book while i am created everything is fine(ok)
but when i am editing every data back in my form without assign user .
how can i get the user in editing form ?? this is my Address Book Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\AddressRequest;
use App\Http\Requests;
use App\Models\Address;
use App\Models\User;
use App\Http\Controllers\Controller;`enter code here`
use Illuminate\Pagination\Paginator;
use Auth;
use DB;
use Session;
class AddressesController extends Controller
{
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index(Request $request)
{
Session::forget('searchaddress');
$addresses = Address::orderby('company_name');
$company_name = $request->input('company_name');
if(!empty($company_name)) {
//$addresses->where('company_name','LIKE','%'.$company_name.'%');
$addresses->where('company_name','LIKE','%'.$company_name.'%');
Session::set('searchaddress', $company_name);
}
$addresses = $addresses->paginate(5);
return view('address.index',compact('addresses'));
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$users = User::lists('first_name','id');
return view('address.create',compact('users'));
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store(AddressRequest $request)
{
$address = Address::create($request->all());
$firstname = Auth::user()->first_name;
$lastname = Auth::user()->last_name;
$address->created_by =$firstname." ".$lastname;
$address->users()->attach($request->input('user_list'));
$address->save();
return redirect('/addresses');
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
$address = Address::find($id);
return view('address.show',compact('address'));
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return Response
*/
public function edit($id)
{ $users = User::lists('first_name','id');
$address = Address::findorFail($id);
return view('address.edit',compact('address','users'));
}
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update( AddressRequest $request ,$id)
{
$address = Address::findOrFail($id);
$address->update($request->all());
$address->users()->sync($request->input('user_list'));
return redirect('/addresses');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
$address = Address::find($id);
$address->delete();
return redirect('/addresses');
}
}
and that is my AddressBook Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Address extends Model
{
protected $fillable = [
'created_by',
'company_name',
'phone',
'email', 'address','comment'
];
public function users()
{
return $this->belongsToMany('App\Models\User')->withTimestamps();
}
public function getUserListAttribute()
{
return $this->users->lists('id');
}
}
[![enter image description here][1]][1]
[1]: http://i.stack.imgur.com/D4jXQ.png
You have belongsToMany relation, so in your edit action you also should get current Address users like this
public function edit($id)
{ $users = User::lists('first_name','id');
$address = Address::findorFail($id);
$address_users = $address->users->lists('id')->toArray();
return view('address.edit',compact('address','users', 'address_users'));
}
then in your view in select you should intersect arrays of $users and $address_users to get selected options.
{!! Form::select('user_list[], $users, isset($address_users) ? $address_users : null, ['id' => 'users_list', 'class' => 'form-control', 'multiple']) !!}
to avoid
isset($address_users) ? $address_users : null
you can define empty address_users array in your create method and do it like this
$address_users
My Controller Action Method is like below:
public function store(Request $request)
{
$IsActive = $request->input('IsActive');
echo $IsActive;
die();
}
My View is like below
{!! Form::open(array('method' => 'POST', 'action' => 'DepartmentController#store')) !!}
{!! Form::checkbox('IsActive', 0, null, array('class' => "flat")) !!}
{!! Form::submit('Save', array('class' => "btn btn-success"))!!}
{!! Form::close() !!}
Problem
On Form submit, I always get value = 0 for CheckBox. Am I missing
something ?
You are getting 0 as value on form submit is because, you have explicitly declared value as 0. Replace 0 with whatever value you want, and you will get the result as per your desire.
From the api source code:
/**
* Create a checkbox input field.
*
* #param string $name
* #param mixed $value
* #param bool $checked
* #param array $options
* #return string
*/
public function checkbox($name, $value = 1, $checked = null, $options = array())
{
return $this->checkable('checkbox', $name, $value, $checked, $options);
}
/**
* Create a checkable input field.
*
* #param string $type
* #param string $name
* #param mixed $value
* #param bool $checked
* #param array $options
*
* #return string
*/
protected function checkable($type, $name, $value, $checked, $options)
{
$checked = $this->getCheckedState($type, $name, $value, $checked);
if ($checked) {
$options['checked'] = 'checked';
}
return $this->input($type, $name, $value, $options);
}
Hope this helps you out.