I would like to ask you about routing in symfony. I know that we can put a route on top of action but I saw a way when putting route on top of class. I want to know what this means? cos when I'm putting route on top of class I'm getting page not found error.
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
/**
* Class DefaultController
* #package AppBundle\Controller
* #Route('/Test')
*/
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
* #Template()
*/
public function indexAction(Request $request)
{
// replace this example code with whatever you need
return $this->render('default/index.html.twig', array(
'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'),
));
}
}
Thanks in advance.
The annotation #Route can work both in Methods and in Classes.
A controller should wrap always methods related by the same topic, for example, CartController. Inside this controller you will have Cart-related methods, so you should be able to define some kind of prefix for all of them.
so, if you have #Route("/cart"), each method's route defined with that annotation will be appended to this prefix /cart. Remember, appended doesn't mean overwritten.
That should work.
Your "Page not found" message has nothing to do with this annotation :)
UPDATE
Some steps to check that your route is being loaded.
Symfony brings you a router debugger. It lists you all found and available routes from your project. From the root of your project, php app/console debug:route. For Symfony 3.*, php bin/console debug:router and for very old Symfony versions... php app/console router:debug.
If the route is not there, make sure that your routes are being loaded. You need to specify to the Framework that your controller needs to be parsed in order to find #Route annotations :)
Check how to load routes from annotations in many ways here
The easy way is...
app:
resource: "#AppBundle/Controller"
type: annotation
Related
I would like to generate a rich snippet for ratings in my TYPO3 pages. The rating information are fetched via an API, so I need some kind of caching mechanism.
I have some basic knowledge and experience with TYPO3 extensions, but I am not sure about the cleanest solution. I could render the meta tags with the TYPO3 Meta Tag API and cache the fetched information using the TYPO3 Caching Framework.
But I am not sure where to store the logic so that it gets executed at every page visit. I do not want to use a content plugin for obvious reasons. Should I set up a Controller and call the Contoller's function with e.g. some hook?
Thanks for any help!
You may have a look at the tslib/class.tslib_fe.php hooks in TypoScriptFrontendController class.
Choose the correct one (maybe tslib_fe-PostProc) and do something like this :
1) Register hook in ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'][] = \Vendor\Name\Hook\AdditionalMetaData::class . '->addRating';
2) Create your class with the following method
<?php
namespace Vendor\Name\Hook;
class AdditionalMetaData
{
/**
* #param array $parameters
* #return void
*/
public function addRating(&$parameters)
{
/** #var TypoScriptFrontendController $tsfe */
$tsfe = &$parameters['pObj'];
// Do your logic here...
}
}
I have an existing web application accessing a MySQL database. I'm porting this application to Symfony. The new application has to use the old database, as we cannot port the whole application at once, i.e. the old and the new application are accessing the same database and the applications are running simultaneously.
The old application had a simple CMS functionality which has to be ported:
There is a table pagewhich represents a page tree. Every page has a slug field. The URL path consists of those slugs representing the path identifying the page node, e.g. "/[parent-slug]/[child-slug]".
The page table also contains a content field. As I already mentioned, the CMS functionality is very simple, so the content is just rendered as page content inside a page layout. The page entry also specifies the page layout / template.
My problem is that I don't know how to set up the routing. In a normal Symfony application I'd know the URL patterns before, but in this case they are dynamic. Also routes cannot be cached, because they could be changed any time by the user. I wonder if I have to drop Symfony's routing completely and implement something on my own. But how?
Now I found Symfony CMF which tells a lot about the framework VS CMS routing conflict. So first, I thought this would be the right way. However the tutorials aim at building an entirely new application based on PHPRC. I wasn't able to derive the tutorial's concepts to my use case.
since you run several URL rules on one symfony application, you will need to work with url prefixes. Either your cms should work with a prefix /cms/parent-slug/child-slug or all other controllers. Otherwise you are not able to differ which controller is meant when a dynamic request arrives.
You can try a workaround with a KernelControllerListener. He will catch up every request and then check if a cms page is requested. On the basis of the request you can set controller and action by yourself. Concept:
Create only one route with "/". Abandon oll other rules. Then create a Listener like this:
<?php
namespace AppBundle\Listener;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
/**
* Class KernelControllerListener
* #package ApiBundle\Listener
*/
class KernelControllerListener
{
/**
* #var CmsRepository
*/
private $requestParser;
/**
* KernelControllerListener constructor.
* #param CmsRepository $CmsRepository
*/
public function __construct(CmsRepository $CmsRepository)
{
$this->CmsRepository = $CmsRepository;
}
/**
* #param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event){
$request = $event->getRequest();
//should be /parent-slug/children/slug or any other path
$path = $request->getPathInfo();
if($this->CmsRepository->getCmsControllerIfMatch($path)){
//cms repository search in db for page with this path, otherwise return false
$event->setController([AppBundle\CmsController::class, 'cmsAction']);
return;
}
//repeat if clause for any other application part
}
}
in services.yml:
app.controller_listener:
class: AppBundle\Listener\KernelControllerListener
arguments:
- "#app.cms_repository"
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
Edit: catch all routes, see https://www.jverdeyen.be/symfony2/symfony-catch-all-route/
The question is: Do you whant to migrate the data or not. For both question, the CMF can be an answer. If you wanna a simple dynamic router, you should have a look into the ChainRouter with an custom router definition:
https://symfony.com/doc/current/cmf/bundles/routing/dynamic.html
and
https://symfony.com/doc/current/cmf/components/routing/chain.html
If you wanna migrate the data, you can use fixture loaders, as we use in almost all of our examples.
I'm used to have model and form validation together, in another framework. But I'm migrating to Laravel and trying to understand its mindset.
What's the best approach for data validation? I've seen some classes that help out on creating forms and validating requests, but isn't it unsafe to have models saving data without validating it before?
How could I integrate form (frontend), request (backend) and model validation so they all play nicely together? Or this is not done in the Laravel world at all?
As a starter in Laravel myself, I can tell a mind of a learner.
The first thing to understand is that Laravel is very very very very very abstract. It offers you thousands of solutions for a single problem. Since you're just starting out, I'm going to assume you're using Laravel 5 (5.1 to be more specific).
The $this->validate() from Controllers
You can use $this->validate() in your controllers.
class SomeController extends Controller {
public function store(Request $request){
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// This passed validation.
}
}
The Validation Facade
Inside the config/app.php you will find a aliases field that defines the Validator Facade as 'Validator' => Illuminate\Support\Facades\Validator::class. You can make validators from basically anywhere.
public function store(Request $request) {
$validator = Validator::make($request->all(), [
'email' => 'required|unique:emails|email',
]);
if ($validator->fails()) {
// Error logic
}
// Store the blog post...
}
Form Requests
Personally, I like Form Requests. They allow you to reuse validation logic defined once in any controller you feel like it. You can run in your project
php artisan make:request MyCustomRequest
That will generate a new request inside app/Http/Requests where you can write your rules inside the rules method. And then, when you want to use it, just type-hint your controller method.
Here is how to use it:
public function store(CompanyRequest $request){
// This code will only be executed if the rules inside CompanyRequest
// Are true.
}
Here is the file defining CompanyRequest.
class CompanyRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize() {
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules() {
return [
'name' => 'required|max:255',
'domain' => 'required|max:40'
];
}
}
Conclusion
There are probably a few more ways to do it. You can, for instance, use Validator::make facade from within your Eloquent models. Laravel offers multiple ways of handling basic problems. You just have to find what is best for you and major in it.
I'm not sure this is the best method or not.
But I'm using this concept and its most popular way of validating forms in most popular CMS.
As usual the form action should point to a controller method. Inside controller method you can init a validator class like below.
$validation = \Validator::make(\Input::all(), with(new UserValidation)->getRules());
if ($validation->fails()) {
return redirect()->route('your route path ')->withErrors($validation)->withInput();
}
Then in your controller use the namespace like .
use VendorName\PackageName\validations\UserValidation;
Here I put the validations in a separate folder called validations. Also notice that I'm using Package development concept in Laravel 5.x you can read more about that here.
Then in that UserValidation class you can put all the validation rules.
class UserValidation {
public function getRules() {
return [
'name' => 'required|max:200|unique:client',
'address'=>'required',
'status' => 'required',
];
}
}
This has several advantage the controller looks much neat and validation customization will be entirely separate file.
Also you can split up the route to a separate folder too.
Hope it make sense..
In the end, the best way I found to solve this matter was stitching together two Laravel extensions: Ardent, an Eloquent extension that includes validation, and a fork of Laravalid, that extends the Form with jQuery basic validation: that fork includes Ardent integration.
I'm taking over a site that's gone through several developers. The site is using Zend version 1.12.0, according to Zend_Version::VERSION, which is a new framework for me. On the site, there's a form class called App_Form_Customers_Edit, which extends Zend_Form. The form's action is /customers/edit, and when submitted, the method editAction of CustomersController is executed.
So, to create a new form, I created a new class App_Form_Customers_EditAddress in the same directory as App_Form_Customers_Edit, and set it's action to /customers/editaddress, created a function called editaddressAction in the CustomersController class and tested the form.
But I get an error saying "Resource 'customers::editaddress' not found"
The form itself is displaying properly, and as far as I can tell I'm using the exact same pattern as the other form which works, and apart from not using the zf command, the same method prescribed here in the Zend documentation: http://framework.zend.com/manual/1.12/en/learning.quickstart.create-form.html
What do I need to do to get my new form working? Do I need to update .zfproject.xml? I can't see anything in there that's related to the working form.
Here's the code for App_Form_Customers_Edit:
class App_Form_Customers_Edit extends Zend_Form
{
public function init ()
{
$this->addPrefixPath('App_Form', 'App/Form/');
$this->setMethod('post');
// ... The rest is just calls to $this->addElement
}
}
And for EditAddress:
class App_Form_Customers_EditAddress extends Zend_Form
{
public function init ()
{
$this->addPrefixPath('App_Form', 'App/Form/')
->setMethod('post')
->setAction('/customers/editaddress');
$this->addElement('submit', 'active', ['value' => 'Activate']);
$this->addElement('submit', 'remove', ['value' => 'Remove']);
$this->addElement('hidden', 'id');
}
}
Check for acl declarations. If you are using acl and you have not declared rules for the action, you might get this type of error.
Best guess:
Your former developer has implemented a custom route somewhere. Probably in the application.ini or the boostrap.php. This custom route is looking for specific urls and /customers/edit conforms to a valid route but /customers/editaddress does not.
I think this is likely because your error is a missing resource rather then a 'page not found' or a missing controller or missing action message. So it seems as though the router is trying to match an invalid resource to a valid route.
Good Luck
I'm writing a custom validator that is going to check for the existence of an email such that if it already exists in the database, the form is not valid. I'm having a hard time figuring out helper paths and namespaces for custom Zend_Validation classes.
I'd like to call the class My_Validate_EmailUnique but I keep getting error messages such as:
there is an error exception 'Zend_Loader_PluginLoader_Exception' with message 'Plugin by name 'My_Validate_EmailUnique' was not found in the registry; used paths: My_Validate_: /var/www/site/arc/helpers/
The class looks like this:
<?php
class My_Validate_EmailUnique extends Zend_Validate_Abstract
{
const EMAIL_UNIQUE = 'notMatch';
Can someone help me with where I register for the Zend_Form to look for custom validators?
You can directly add the validator to your form element. There is no need to write a custom validator for this.
In your form:
$element->addValidator(new Zend_Validate_Db_NoRecordExists('mytablename', 'myemailcolumnname'));
+1 for Db_NoRecordExists - the docs have an example showing exactly what you want to do.
Otherwise, custom validators can be loaded like regular library classes, so try placing it on your include path.
/library/My/Validate/EmailUnique.php
You can also add a new entry to the Zend_Application_Module_Autoloader if you want to keep it in your application folder, as opposed to your library:
// Bootstrap.php
protected function _initAutoloader()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'My_',
'basePath' => dirname(__FILE__),
));
$autoloader->addResourceType('validator', 'validators', 'Validate')
return $autoloader;
}
And put the class My_Validate_EmailUnique in:
/application/validators/EmailUnique.php
I've never registered a custom validator as a plugin before, so I can't help you there sorry.