Where do I store misc functions? How do I use them? Should it be a DependencyInjection? Should it just be a class and do I do something like use Acme\Bundle\AcmeBundle\Misc\ClientIPChecker?
Say I have a function:
<?php
class ClientIPChecker {
public static function isLocal(Request $request){
return in_array('127.0.0.1', $request->getClientIp())
}
}
And I want to use this function in two controllers. How do I do this in Symfony2?
If you have a set of consistent function put them in a class/service. If functions do different things put them in the appropriate class/service. In this particular case, I'll go for either custom Request or custom Controller (probably the latter, avoding messing app.php or app_dev.php).
With custom controller this doesn't work:
// Automatic binding of $request parameter
public function indexAction(Request $request)
{
// Won't work with custom controller
if ($request->isLocal)) {
// ...
}
// You have to do
if ($this->getRequest()->isLocal()) {
// stuff
}
}
Option 1: extend Symfony Request
namespace My\HttpFoundation;
use Symfony\Component\HttpFoundation\Request as BaseRequest;
class Request extends BaseRequest
{
public function isLocal()
{
return in_array('127.0.0.1', $this->getClientIp());
}
}
Then in web/app.php and web/app_dev.php modify:
use Symfony\Component\HttpFoundation\Request;
to be:
use My\HttpFoundation\Request;
Option 2: create a BaseAbstractController and use it instead of Symfony controller
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
abstract class BaseAbstractController extends Controller
{
public function isRequestLocal()
{
return in_array('127.0.0.1', $this->getRequest()->getClientIp())
}
}
Option 3: custom service as explained here
Related
I am new to Laravel. I have some functions in PaymentController. I want to call those functions from SmartpaySController. Here is the function which is available in PaymentController. Help me to call that function by staying in SmartpaySController.
public function getPaymentFailed($paymentId) {
$transactionData = $this->paymentRepo->find($paymentId);
if($transactionData) {
$data['quote'] = $this->quoteRepo->getQuoteById($transactionData->quote_id);
$data['metaTitle'] = 'Payment failed';
$data['returnMessage'] = $transactionData->return_message;
return view('payment::payment.quote_payment_failed', $data);
}
}
Thank you.
Instead of calling controller methods, the better practice is that you can create traits like: app/Traits and extend in controller
//trait
trait traitName {
public function getData() {
// .....
}
}
//Controller
class ControlelrName extends Controller {
use TraitName;
}
I recomend you to not call functions from one controller to another.
Make Helpers, Resources or implement same feature in other way
Never use controllers as object
But if you want to do it anyway you can use:
SomeController.php
class SomeController extend Controller {
public function someFunction(Request $request) {
// Here Some Code
}
}
YourController.php
use SomeController;
...
public function getPaymentFailed(Request $request, $paymentId) {
$controller_data = (new SomeController)->someFunction($request);
$transactionData = $this->paymentRepo->find($paymentId);
if($transactionData) {
$data['quote'] = $this->quoteRepo->getQuoteById($transactionData->quote_id);
$data['metaTitle'] = 'Payment failed';
$data['returnMessage'] = $transactionData->return_message;
return view('payment::payment.quote_payment_failed', $data);
}
}
Change:
public function getPaymentFailed($paymentId)
to:
public static function getPaymentFailed($paymentId)
This will make it staticly available in your SmartpaySController by doing:
PaymentController::getPaymentFailed($paymentId);
You can make use of Real-Time Facades
Using real-time facades, you may treat any class in your application
as if it were a facade.
To generate a real-time facade, prefix the namespace of the imported
class with Facades:
//...
use use Facades\App\Http\Controllers\SomeController;
//...
return SomeController::getPaymentFailed($request, $paymentId);
I'm building an application, now i'm created a helper
class Students{
public static function return_student_names()
{
$_only_student_first_name = array('a','b','c');
return $_only_student_first_name;
}
}
now i'm unable to do something like this in controller
namespace App\Http\Controllers;
class WelcomeController extends Controller
{
public function index()
{
return view('student/homepage');
}
public function StudentData($first_name = null)
{
/* ********** unable to perform this action *********/
$students = Student::return_student_names();
/* ********** unable to perform this action *********/
}
}
this is my helper service provider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
foreach(glob(app_path().'/Helpers/*.php') as $filename){
require_once($filename);
}
}
}
i event added it as an alias in config/app.php file
'Student' => App\Helpers\Students::class,
Try putting use App\Helpers\Student; at the top of your controller beneath the namespace delcaration:
namespace App\Http\Controllers;
use App\Helpers\Student;
class WelcomeController extends Controller
{
// ...
Look more into PHP namespaces and how they are used, I believe you may have a deficient understanding about them. Their only purpose is to make so you can name and use two classes with the same name (e.g. App\Helpers\Student vs maybe App\Models\Student). If you needed to use both of those classes inside of the same source file, you can alias one of them like this:
use App\Helpers\Student;
use App\Models\Student as StudentModel;
// Will create an instance of App\Helpers\Student
$student = new Student();
// Will create an instance of App\Models\Student
$student2 = new StudentModel();
You do not need to have a service provider for this, just the normal language features. What you would need a service provider for is if you wanted to defer the construction of your Student object to the IoC:
public function register()
{
$app->bind('App\Helpers\Student', function() {
return new \App\Helpers\Student;
});
}
// ...
$student = app()->make('App\Helpers\Student');
You should never have to include or require a class file in laravel because that is one of the functions that composer provides.
You do not need a service provider to make it works. Just lets the Students class as you did:
class Students{
public static function return_student_names()
{
$_only_student_first_name = array('a','b','c');
return $_only_student_first_name;
}
}
all its methods should be static
You added the Facade correctly:
'Student' => App\Helpers\Students::class,
Finally, looks like your problem is caused by forgetting a backslash at facade name. Uses \Students instead of Students:
public function StudentData($first_name = null)
{
$students = \Student::return_student_names();
}
When using a facade, it is not necessary makes nay include, the facades were made to avoid complex includes in everywhere.
Assuming I have an application using a lot of AJAX requests.
Is there a way to edit Symfony behavior and autommatically call indexAjaxAction instead of indexAction when my request is AJAX made ?
I already know that I can test if a request is Ajax with the Request::isXmlHttpRequest() method but I want it to be autommatic (i.e without testing in each controllerAction).
Does a service/bundle already makes it ?
Example :
<?php
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class FooController extends Controller
{
public function indexAction($vars)
{
$request = $this->getRequest();
if($request->isXmlHttpRequest()) {
return $this->indexAjaxAction($vars);
}
// Do Stuff
}
public function indexAjaxAction($vars){ /* Do AJAX stuff */ }
}
becomes
<?php
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class FooController extends Controller
{
public function indexAction($vars) { }
public function indexAjaxAction($vars) { }
// Other functions
}
One way would be to use a slightly modified controller resolver that would be used instead of the current controller resolver in the regular KttpKernel::handleRaw process.
Please note that I may be wrong in my thinking here and it is untested.
The controller resolver class has the id controller_resolver.class which you could overwrite with your custom one in your config using
In your app/config/config.yml...
.. config stuff ..
parameters:
controller_resolver.class: Acme\SomeBundle\Controller\ControllerResolver
And then in your new ControllerResolver...
namespace Acme\SomeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver
as BaseControllerResolver;
class ControllerResolver extends BaseControllerResolver
{
/**
* {#inheritdoc
*/
public function getArguments(Request $request, $controller)
{
if (is_array($controller) && $request->isXmlHttpRequest()) {
$action = preg_replace(
'/^(.*?)Action$/',
'$1AjaxAction',
$controller[1]
);
try {
$r = new \ReflectionMethod($controller[0], $action);
return $this->doGetArguments(
$request,
$controller,
$r->getParameters()
);
} catch( \Exception $e) {
// Do nothing
}
}
return parent::getArguments($request, $controller);
}
}
This class just extends the current controller resolver and will attempt to use the youractionAjaxAction if it exists in the controller and then falls back to the regular resolver if it gets an error (method not found);
Alternatively you could just use...
if (is_array($controller) && $request->isXmlHttpRequest()) {
$controller[1] = preg_replace(
'/^(?P<action>.*?)Action$/',
'$1AjaxAction',
$controller[1]
);
}
return parent::getArguments($request, $controller);
.. which would just update the called action and then send it through to the regular resolver with no fall back, meaning that every action that could be called using an XmlHttpRequest would require a corresponding AjaxAction.
You may want to look into FOSRestBundle for Symfony, it can be very useful if you have 1 action that can either return json data or rendered html template depending on the request method
I want to use this code in my application:
class ControllerExtension extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
//etc.
}
}
But where do I put it and how do i activate it? I'm guessing it's something to do with the services.yml file. I've used Event Listeners, but this is obviously different.
From your code snippet (http://justpaste.it/2caz), it seems that you missed the "return" keyword in your call to parent.
class ControllerExtension extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
if($this->getRequest()->getRequestFormat() == 'json') {
return new Response(json_encode($parameters));
} else {
// Missing 'return' in your snippet
return parent::render($view, $parameters, $response);
}
}
}
class MyController extends ControllerExtension
{
public function indexAction()
{
// This should now work
return $this->render(...);
}
}
You can put it in your bundle's Controller directory i.e src/YourNamespace/YourBundleName/Controller/ControllerExtension.php.
Make sure you provide the appropriate namespace in that file:
namespace YourNamespace\YourBundleName\Controller;
class ControllerExtension extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
...
To use it, either create a route for it in src/YourNamespace/YourBundlename/Resources/config/routing.yml
or
extend it:
namespace YourNamespace\YourBundleName\Controller;
class OtherController extends ControllerExtension
{
...
If what you are actually looking to do is override another bundle's controller, see the cookbook which describes overriding controllers.
Edit:
As far as I know, there's no way to automatically make this controller somehow take effect. You can have each of your controllers extend it as I've indicated above.
You might be able to create an event listener and use the response event to somehow change the response if the format is json. But, I'm not sure how you would access the view data from the event listener.
I want to make some action (php script) before all actions in my frontend app and then pass a result from that script to actions in variable - so I can get variable value from all actions. Where should I declare sth like this?
If the filter solution dont feet your needs, you can also create a base action class with a preExecute function:
// app/frontend/lib/baseActions.class.php
class baseActions extends sfActions
{
public function preExecute()
{
$this->myVar = .... // define your vars...
}
}
Then your module actions class extends your baseActions class:
// app/frontend/modules/myModule/actions/actions.class.php
class myModuleActions extends baseActions
{
public function executeIndex(sfWebRequest $request)
{
// var $this->myVar is available in any action and in your template
...
}
}
if you have to use the preExecute function in your module class action, remember to call parent::preExecute() in it.
What kind of information ?
I would recommend you to use filters.
In your apps/frontend/config/filters.yml:
rendering: ~
myfilter:
class: myCustomFilter
Create the file lib/filter/myCustomFilter.php:
<?php
class myCustomFilter extends sfFilter
{
public function execute ($filterChain)
{
if ($this->isFirstCall())
{
// do what ever you want here.
$config = Doctrine_Core::getTable('Config')->findAll();
sfConfig::set('my_config', $config);
}
$filterChain->execute();
}
}
And then, every where, you can retrieve your data:
sfConfig::get('my_config');