I'm new to Symfony and I have created many twig html templates and this function to route in my Controller:
/**
* #Route("/{path}")
*/
public function renderTemplate($path) {
return $this->render('/'.$path.'/index.html.twig');
}
?>
The renderTemplate() function works fine for all first level folders, but not for subdirectory files, because it seems like it interrups after a "/". I don't want to write dozens of new Route functions.
How can I implement all sites including subdirectories separated by "/"?
What is a safe practice and easy solution?
The structure of my twig templates folder is this:
Templates folder
#Routeis your URL, not your file path.
The default path in Symfony (3.4) is app/Ressources/view/
Thus, if you want to reach app/Ressources/view/default/index.html.twig, you will do this:
return $this->render('default/index.html.twig');
I just found the answer to be here in the Symfony documentation.
Apparently, you can allow "/" in your variable like this:
use Symfony\Component\Routing\Annotation\Route;
class DefaultController
{
/**
* #Route("/share/{token}", name="share", requirements={"token"=".+"})
*/
public function share($token)
{
// ...
}
}
I named all my twig templates "index.html.twig" and put them in the corresponding file path in my templates folder and now my function is working very smoothly for every site.
I may have to change it later to do individual requests, but it was a convienient short-term solution to be able to see all my pages with easy and nice-looking links and only one route function in my controller.
Related
I am unable to create Controllers through the Command line. Does anyone know how can I manually create controllers for my Symfony2 project?
What files I need to update?
You should create file YourControllerNameController.php at src/YourBundle/Controller folder. And put class with name YourControllerNameController into this file. Also be assured that you wrote right namespace according to PSR-0.
If you create controller as a service you can define it as a service and have no problem.
If you want create standard controller that are not registered at service container you could extend your class from Symfony\Bundle\FrameworkBundle\Controller\Controller
In both cases you need also define route for your actions. The easiest way would be to define one route with annotation type. It will generate routes automatically based on your annotations related to actions:
your_route_name:
resource: "#YourBundle/Controller"
type: annotation
It will scan your src/YourBundle/Controller folder and will generate new route for any method in any class in any file that will have annotation #Route:
/**
* #Route("/your/path", name="you_can_specify_name_here_but_it_is_optional")
*/
public function yourAction()
{
// Your code here
}
Since a week I'm in love with Symfony2. I've a feedbackmessagebundle: src/Erwine/FeedBackMessageBundle .
I put some custom classes from another project in: src/Erwine/FeedBackMessageBundle/FeedBackMessage.
All classes has the same namespace: Erwine\FeedBackMessageBundle\FeedBackMessage.
I've several implementations in different files. Let's say:
- FeedBackMessageClassOne
- FeedBackMessageClassTwo
- FeedBackMessageClassThree
The first one lives in his own file. If Two extends from One I got a failure. I've tried use... etc.
Two and Three lives as twins in the same file. If Three inherits from Two, it works.
An instance of One in the controller is no problem.
It seems to me, the inheritance of classes in the same namespace in different files doesn't work. No, no, no, course not, I do something wrong. Isn't it? But what? Is it autoloading in Symfony2 for custom classes?
I am using composer for the dependencies.
UPDATE
Here is my implementation:
<?php
namespace Erwine\FeedBackMessageBundle\FeedBackMessage;
class FeedBackMessageHandlerImpl extends FeedBackMessageHandlerImplTwee
{
public function __construct()
{
//var_dump('constructed');
//parent::__construct();
}
//public function getFeedBackMessageGeneralOverride(){};
}
Provided your autoloading is set up correctly, it should just be something like this:
Folder structure:
src/
Erwine/
FeedBackMessageBundle/
FeedBackMessage/
FeedBackMessageClassOne.php
FeedBackMessageClassTwo.php
FeedBackMessageClassThree.php
FeedBackMessageClassOne.php:
<?php
namespace Erwine\FeedBackMessageBundle\FeedBackMessage;
class FeedBackMessageClassOne
{
// Contents of class...
}
FeedBackMessageClassTwo.php:
<?php
namespace Erwine\FeedBackMessageBundle\FeedBackMessage;
class FeedBackMessageClassTwo extends FeedBackMessageClassOne
{
// Contents of class...
}
You shouldn't need a use statement for the extend in the second file as the file resides in the same namespace, therefore by defining the same namespace in the second class, you are able to use the first class without the use statement.
Make sure that your autoloading is set up properly.
It's important that you keep every class in a separate file, and also that you name the files the same as the classes.
This is because Symfony uses PSR-0 by default if you're using the composer autoloader. Go here to read more about PSR-0
I try to create an Admin User with FOsUserBundle from command windows with the following command:
php app/console fos:user:create
In my project the Admin User extends other user with mandatory propriety. So, when I choose my username, mail and password, it tells me:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'latitude' cannot be null
How can I set the value "latitude" in my AdminUser? I also use PUGXMultiUserBundle.
Only possibile way to reach that to me is
1 - override the cli command of FOSUserBundle placed into Command/CreateUserCommand.php
2 - override the user create method of FOSUserBundle placed into Util/UserManipulator.php
// Command/CreateUserCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = $input->getArgument('username');
$email = $input->getArgument('email');
$password = $input->getArgument('password');
$inactive = $input->getOption('inactive');
$superadmin = $input->getOption('super-admin');
$latitude = $input->getOption('latitude'); //this will be your own logic add
$manipulator = $this->getContainer()->get('fos_user.util.user_manipulator');
$manipulator->create($username, $password, $email, $latitude, !$inactive, $superadmin);
$output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}
and
// Util/UserManipulator.php
public function create($username, $password, $email, $latitude, $active, $superadmin)
{
$user = $this->userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setPlainPassword($password);
$user->setEnabled((Boolean) $active);
$user->setSuperAdmin((Boolean) $superadmin);
$user->setLatitude($latitude);
$this->userManager->updateUser($user);
return $user;
}
Of course when I say override i mean ... override :P So you haven't to modify FOSUserBundle original files (you know, it's dangerous for many reasons) but make your own files by making your bundle extended by FOSUserBundle
Are you wondering how to make your bundle extended by FOSUserBundle?
Into your bundle "mainfile" - is the one you use to register your bundle - just add this lines
public function getParent()
{
return 'FOSUserBundle';
}
Then you simply recreate the tree structure where your ovverride files lives into original bundle, into your custom bundle's Resources/ directory (same position, same file name, same annotations if any) and .... the magic can start :) (this is valid only for views, please pay attention!)
What "override" means?
Override means that you take an existent function, "shadow" it by redefining elsewhere (declare a function with the same name, no matter how many parameters it accept, no matter the type of paramenters since php doesn't support method overloading [except if you do some "hack"]) and then you can use it instead of the original one. This is a common technique for add extra functionalities to a function or to change the function itself.
Say that we have two classes, A and B with B that is a child class of A. Say also that A have a method called myMethod().
In B we can do something like
public function myMethod() {
parent::myMethod();
//add extra functionalities here
}
in that way we're adding extra functionalities as we're calling the parent ("original") method and then execute some extra functionalities
Whereas if in B we make something like
public function myMethod() {
//some code here, but not calling parent method
}
we're redefining the behaviour of myMethod()
How Symfony2 let me override methods?
As I said previously in my answer, you have to make your bundle a child of the bundle that containts the function(s) you're trying to override (in that case FOSUserBundle). Once you did it, use the Resources directory of your bundle to accomplish what you need. reproduce the "tree-folder-structure" of the original bundle (ie.: same names of the folders) until you reach the class that contains the function you need to override.
Follow your real example: you need to override execute() function contained in Command/CreateUserCommand.php. You have to create, into your bundle folder that path:
PathTo/YourCostumBundle/Command/
and place inside the file CreateUserCommand.php with the content I show you above.
If you don't understand where I find that path, please take a look to FOSUserBundle code and it will be absolutely clear!
Why is dangerous to modify the FOSUserBundle code directly?
Well, there's a lot of answer an critic point that I can show you. Choosing the main (not ordered for importance):
What if you need to update FOSUserBundle? You'll use composer and lost every modify that you made to FOSUserBundle code
What if you have more than one bundle into your project that need to use FOSUserBundle? Maybe the custom behaviour makes sense for a bundle but not for the other one. Costumizing the behaviour at local bundle level helps you to keep FOSUserBundle logic intact
What if you're developing a bundle that you want to share with other user? You need to force them to "take" your own costumized FOSUserBundle version and warn them about updating it
Finally: I perfeclty know that your entity isn't into FOSUserBundle, but I can bet that they extend FOSUserBundle base user so what I told above is applicable to your case.
Hope it's less fuzzy now :)
Documentation: http://symfony.com/doc/current/cookbook/bundles/inheritance.html#overriding-controllers
I always follow the pattern I learned in the symfony documentation itself:
php bin/console fos:user:create usertest mail#domain.com password
and sometimes I need change the "roles" on the table "fos_user"
then
a:0:{}
to
a:1:{i:0;s:10:"ROLE_ADMIN";}
After creating a user with:
bash-5.1# bin/console fos:user:create admin admin#mydomain.com password123
Promote the user with the ROLE_ADMIN role:
bash-5.1# bin/console fos:user:promote
Please choose a username:admin
Please choose a role:ROLE_ADMIN
Role "ROLE_ADMIN" has been added to user "admin". This change will not
apply until the user logs out and back in again.
Is there a way to override the controller file located at /concrete/blocks/page_list/controller.php and place it inside /packages/mypackage/blocks/page_list/? I'd like to make some changes to the original edit and view.
In /packages/mypackage/blocks/page_list/controller.php, I tried doing this but it does not seem to have any effect:
class PageListBlockController extends Concrete5_Controller_Block_PageList { ... }
You can now override/extend core classes via packages in newer versions Concrete5 (v.5.6+).
You must add to your package's main controller.php file:
public function on_start(){
$objEnv = Environment::get();
$objEnv->overrideCoreByPackage('blocks/page_list/controller.php', $this);
}
You don't have to copy over the whole core controller, just declare your new block controller like this:
class PageList extends Concrete5_Controller_Block_Page_List {
public function mymethod() {
}
}
(what class you're extending and where you put the file may vary depending on your C5 version - just compare the /concrete/ folder structure and files for reference)
The following C5 forum posts may be of help:
Overriding Core Class with Package
Can A Package Override A Core Library?
A caution, though - if you're hoping to submit to the official C5 marketplace, they generally don't accept Add-Ons with overrides.
No. You can't override a block controller from within a package. Just imagine if more than one package did this. (You can, however, have a block template within your package directory, but this makes sense because it adds rather than replaces.)
If you can, you should override by putting it in /blocks/page_list/controller.php.
However, if you still need to override it from you package, you should look into the not-very-well-supported Environment::overrideCoreByPackage() and try:
Environment::get()->overrideCoreByPackage('/blocks/page_list/controller.php', $myPackage);
See the source:
https://github.com/concrete5/concrete5/blob/master/web/concrete/core/libraries/environment.php#L123
And an example of usage:
http://www.concrete5.org/community/forums/customizing_c5/override-a-core-class-within-a-package/#460765
I know that I can set Twig variables in my app/config/config.yml, however I want to set variables on a per bundle level (eg: Bundle/Resources/config/??.yml).
For example I want to include a bundle version identifier in the footer of my pages. I tried placing twig config into my bundles' services.yml however Symfony wasn't able to parse the configuration.
How can I achieve this?
I'm not sure how you could implement bundle specific configs for your example. The configs in bundles tend to be imported into the main config files which are now environment specific rather than bundle specific.
However, for your example I would just make a twig extension which returns the name of the bundle you're using. That way you can use it wherever you like in your templates. You can get the fully named route of your controller from the request, then just use preg matching to get the Bundle name. Something like the below should work:
public function getBundleName()
{
$pattern = "#([a-zA-Z]*)Bundle#";
$matches = array();
preg_match($pattern, $this->container->get('request')->get('_controller'), $matches);
return $matches[1];
}
In this example $this->container has been set in the constructor to be an instance of the container. If you are using another method to get the controller then substitute accordingly.