Default forgot password form is an Email form field. I have a licence number attached to each user. As a user, I want to get the reset password link by entering my licence number instead of email.
I've found a way around to override the functionality side but not the form. What I've done till now
Filename: _config.php
Object::useCustomClass('MemberLoginForm', 'ExtendLoginForm');
Filename: ExtendLoginForm.php
Just as a test - override forgotPassword method
class ExtendLoginForm extends MemberLoginForm
{
public function forgotPassword($data) {
// Ensure password is given
$this->sessionMessage('This works', 'bad');
$this->controller->redirect('Security/lostpassword');
return;
}
}
Session message is successfully printed with a redirect to the same page.
How can I override the form to make it a Text field instead of Email field.
First, just a general tip, you should avoid using Object::useCustomClass() in favour of Injector (https://docs.silverstripe.org/en/3.0/reference/injector/). Object::useCustomClass() is more of a 2.4 thing.
The forgot password form is generated in Security. You can try using a custom implementation of that class as well, and overloading the ForgotPasswordForm method.
config.yml
Injector:
Security:
class: MyCustomSecurity
MyCustomSecurity.php
class MyCustomSecurity extends Security
{
public function LostPasswordForm()
{
$form = parent::LostPasswordForm();
$form->Fields()->replaceField('Email', TextField::create('Email'));
return $form;
}
}
Related
I need to check if a user is using a mobile device upon connecting to the website.
I need to make an eventListener further on.
in the Symfony doc there is a passage where actually you can check this $request->headers->get('User-Agent')
Is there a simple way to do that?
--- EDIT ---
this is the code I wrote so far. I'm missing maybe on how to pass it to the controller?
service
template.loader:
class: ST\BackofficeBundle\EventListener\DeviceListener
tags:
- { name: kernel.event_listener, event: kernel.view, method: onKernelView }
listener
class DeviceListener
{
public function onKernelView(getResponseEvent $event)
{
$event->getRequest()->getSession()->set('mobile', true);
$response = new Response();
$response->setContent($event);
$event->setResponse($response);
}
}
Am I on the right track ?
You could have a look at https://github.com/kbond/ZenstruckMobileBundle code
It creates an EventListener here:
https://github.com/kbond/ZenstruckMobileBundle/blob/master/EventListener/RequestListener.php
And based on that, overwrites the twig render here:
https://github.com/kbond/ZenstruckMobileBundle/blob/master/Twig/TwigEngine.php
Both things get wired up through
https://github.com/kbond/ZenstruckMobileBundle/blob/master/Manager/MobileManager.php
I'm working on a symfony2 application and I want to create a security session and role without using FOSUserBundle.
example :
class AuthentificationController extends Controller {
//login
public function logincheck(Request $req) {
// ----code
//
//--> create a user session
}
}
// in twig
<!-- here verification : if user is connected see user-space
else redirect
-->
<!-- admin space -->
In symfony docs there is an example of how to create authenticationProvider and how to check user for valid session
I'm using SonataAdminBundle with Symfony 2.2 and want to display the dashboard blocks depending on what user is logged in.
e.g.
Users with Group Superadmin will see blocks 'UserManagement' and 'Messages'
Users with Group Staff will see only block 'Messages'
I read the whole documentation especially the security doc but found no info on how to restrict the dashboard view. I already implemented a filter which will will show no entries in the list view of an entity class if the user's permissions are not enough.
But it would be way better to not show him the blocks at all.
Any ideas on how to do this ?
Well, for anyone running into this, I solved it by simply returning an empty Response in execute(). My use-case was one where I wanted to show a block to users with a specific role:
First I defined my service for using the security.context service like so:
sonata.block.service.foo:
class: Acme\DemoBundle\Block\FooBlockService
arguments: [ "sonata.block.service.foo", "#templating", "#doctrine", "#security.context" ]
tags:
- { name: sonata.block }
Then I defined the block service __construct() as:
//Acme\DemoBundle\Block\FooBlockService
public function __construct($name, EngineInterface $templating, $doctrine, $securityContext)
{
parent::__construct($name, $templating);
$this->doctrine = $doctrine;
$this->securityContext = $securityContext;
}
Finally, in the execute function the first thing I did was check for a specific role on the user like so:
//Acme\DemoBundle\Block\FooBlockService
public function execute(BlockContextInterface $blockContext, Response $response = null)
{
if( $this->securityContext->isGranted("ROLE_ACME_FOO") === false )
{
return new Response();
}
//... more code
This works, but it feels like a hack. Mainly, because the Block goes through all of its stages, and only on the output it return nothing, meaning overhead. A better solution would be to somehow prevent the entire Block from being loaded, based on some custom code.
In conclusion, this isn't the best way, but it worked for me!
You can restrict access to block using roles, like this:
sonata_admin:
dashboard:
blocks:
- { position: top, type: your_service_block_name, class: 'col-xs-4', roles: [ROLE_SOME_NAME_HERE_, ROLE_SOME_NAME_HERE_2] }
You can check under SonataAdminBundle:Core:dashboard.html.twig how this roles works:
{% if block.roles|length == 0 or is_granted(block.roles) %}
<div class="{{ block.class }}">
{{ sonata_block_render({ 'type': block.type, 'settings': block.settings}) }}
</div>{% endif %}
I am working with Symfony2. I have two fields in a form builder, when I select a choice in the first field, information in the second field should be reloaded dynamically according the first choice.
How can I do it ?
What do we need?
Let's say for the sake of simplicity you need when the user type in 'knock knock' the next field is filled with 'who's there'.
Assuming that the first field (which the user will fill) has an id of #input_filled_by_user and the other field's id is #input_filled_with_php.
How do we solve this?
As long as the user will be typing after the script is executed, we need something to tell us the he wrote the specific word in or case 'knock knock' (which is jQuery), and send it to a controller (a fancy name for rest API).
And then in the controller we process and send back result, and with jQuery (again) we output the result to the user.
The code
First we need a router:
my_door_keeper_router:
pattern: /request/{string}
defaults: { _controller: AcmeDemoBundle:door:keeper, _format: ~ }
requirements:
_method: GET
id: "\d+"
And here is the action controller:
public function keeperAction($string)
{
if ($string == 'knock knock') {
echo "hello"; // please dont do it with echo use symfony way , i just dont have enough time
}
return;
}
Now with jQuery:
$('#input_filled_by_user').change(
function(){
$.get('/request', { string: $(this).val() } ,function(data) {
$('#input_filled_with_php').val(data);
alert('Load was performed.');
});
}
)
And that's it. Hope this makes sense (please dig deeper, I tried to explain it the dummy way, and some of the things i mentioned are half correct, but for whatever you're trying to do now you will be fine doing so).
I built a custom module that manages appointments for a service-based company. All of the current functionality is contained in the admin section. I have not used a single ContentItem or ContentPart. All the models are just plain records.
I'm looking to create a widget to expose the ability to sign up for an appointment from the front end. I have a partial view and a controller that handles the display and form submit, but I'm not sure how to tie that into a widget that can be placed in one of the content zones of the front-end.
I've spent quite a bit of time researching this, and can't find a good path to follow. (I've tried a few and got sub-optimal results)
Any suggestions?
The best answer for me was to create a widget Type definition in the migration.cs file of the module:
ContentDefinitionManager.AlterTypeDefinition("CreateAppointmentWidget",
cfg => cfg
.WithPart("WidgetPart")
.WithPart("CommonPart")
.WithSetting("Stereotype", "Widget"));
Then create a handler for that widget at /MyModule/Handlers/CreateAppointmentWidgetHandler.cs:
public class CreateAppointmentWidgetHandler : ContentHandler
{
private readonly IRepository<FieldTechRecord> _repository;
public CreateAppointmentWidgetHandler(IRepository<FieldTechRecord> repository)
{
_repository = repository;
}
protected override void BuildDisplayShape(BuildDisplayContext context)
{
base.BuildDisplayShape(context);
if (context.ContentItem.ContentType == "CreateAppointmentWidget")
{
CreateAppointmentViewModel model = new CreateAppointmentViewModel(_repository.Fetch(x => x.IsActive));
context.Shape.AppointmentModel = model;
}
}
}
Then create a matching widget template at /MyModule/Views/Widget-CreateAppointmentWidget.cshtml that inserts the Partial View:
#Html.Partial("CreateAppointment", (MyModule.Models.Views.CreateAppointmentViewModel)Model.AppointmentModel)
The above code grabs the partial view /MyModule/Views/CreateAppointment.cshtml.
Thanks to Giscard's suggestion, I was able to correct the links rendered from CreateAppointment.cshtml by using #Url.RouteUrl() and defining named routes to point where I needed the action and ajax requests to go.
The nice thing about this solution is that it provided a way to create the widget without having to rework my models to use Orchards ContentPart functionality.
Something is not connecting in my head, because I have been able to create a theme with zones, and then dispatch a shape from my module into that zone without much more than doing #Display.Shape(). So I am curious if it's absolutely necessary to use a handler to override the BuildDisplayShape.
Again, this is in the scenario where you have models as plain records (not using ContentItem or ContentPart - and even if not using them, you've shown an example of creating one through migrations).
Something like this - Controller:
public ShapeResult MyShape()
{
var shape = _orchardServices.New.MyPath1_MyShape();
return new ShapeResult(this, shape);
}
Then create a MyShape.cshtml shape with whatever code I have (no need for example).
NOTE: I use a custom IShapeTemplateHarvester file which adds paths where I can store my shapes (instead of using "Views", "Views/Items", "Views/Parts", "Views/Fields", which is the stock in Orchard). It goes something like this:
NB: I hate that code doesn't automatically wrap in SO.
[OrchardSuppressDependency("Orchard.DisplayManagement
.Descriptors.ShapeTemplateStrategy.BasicShapeTemplateHarvester")]
public class MyShapeTemplateHarvester : BasicShapeTemplateHarvester,
IShapeTemplateHarvester
{
public new IEnumerable<string> SubPaths()
{
var paths = base.SubPaths().ToList();
paths.Add("Views/MyPath1");
paths.Add("Views/MyPath2");
return paths;
}
}
Say I have Index.cshtml in my Theme. I have two choices (I use both and use the Theme as the default presentation).
Index.cshtml in Theme folder:
#*Default Content*#
Index.cshtml in Module folder:
#*Special Content overriding Theme's Index.cshtml*#
Display.MyPath1_MyShape()
Even better for me is that I can do this in the Index.cshtml in Theme folder:
#*Whatever content*#
Display.MyPath1_MySecondShape()
There is no ~/MyPath1/MySecondShape.cshtml in the Theme, but there is one in the Module, which the Theme displays! This is great because I can have a special Theme and have multiple modules (that are placed on separate sites) go back and forth with the theme (think Dashboard for different services in the same profession on different sites).
NOTE: The above may only be possible with IThemeSelector implementation such as:
public class MyThemeSelector : IThemeSelector
{
public ThemeSelectorResult GetTheme(RequestContext context)
{
if (MyFilter.IsApplied(context))
{
return new ThemeSelectorResult { Priority = 200,
ThemeName = "MyDashboard" };
}
return null;
}
}
Just my two bits.