I have a couple of functions which i use in all controllers like this:
//ajax
public function region()
{
return Region::all();
}
//ajax
public function provinces(Request $request)
{
if(!empty($request->input('region_select')))
{
$id_region = $request->input('region_select');
return Region::find($id_region)->Provinces;
}
else{
return Province::all();
}
}
Is it correct to extend the base controller with these functions to have them available globally?
Or is there a safer and more elegant approach?
Thanks in advance.
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 want to restrict or give access to all of my fuction inside a controller by checking some condition in cakephp 3.6.
Suppose I have add(), edit(), view($id) function in my PostController.php . Now I have an input field where user will put an unique id. If this id is present in the database then I want to give access to those function. Oterwise it should show a message to the user.
I am new in cakePHP, so I don't have much idea about cakePHP.
I have tried using beforeFilter. But it is not working.
Here is the code that I have tried. Right now I am not checking with database. Just checking if code is given in input field or not.
public function beforeFilter(Event $event)
{
if(!empty($event->subject()->request->data)){
return true;
}
else{
return false;
}
}
I know maybe those are not proper. But I am not getting proper idea even not proper documentation also.
Here is my controller code structure.
use App\Controller\AppController;
use Cake\Event\Event;
class CodesController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
}
public function beforeFilter(Event $event)
{
if(!empty($event->subject()->request->data)){
return true;
}
else{
return false;
}
}
public function add()
{
//code will be here
}
public function view($id)
{
//code will be here
}
}
Instead of return true from your beforeFilter, use:
$this->Auth->allow(['add', 'edit', 'view']);
No need to do anything in the false case.
Alternately, if those are your only functions, you can simplify to:
$this->Auth->allow();
More details in the manual.
Question might be unclear. here's the explanation. Let's say I've:
Route file:
Route::get('testing', 'someController#functionOne');
Route::get('testingtwo', 'someController#functiontwo');
Controller file:
public function functionOne() {
$this->data = generateReallyBigArray();
return redirect('testingtwo');
}
public function funtionTwo() {
// Here $this->data is lost. obviously 'coz this controller file got reinstantiated for #functionTwo
return view('someview', ['data' => $this->data]);
}
$this->data is lost the moment testingtwo is hit. How do I pass this data across different route requests? Or if there're other ways of doing it.
I was thinking of doing this:
public function functionOne() {
$this->data = 'somedata';
return $this->functionTwo();
}
public function funtionTwo() {
// Here $this->data is lost. obviously 'coz this controller file got reinstantiated for #functionTwo
// even this doesn't work. Exception: Method get does not exist
return Route::get('testingtwo', function() {
return view('someview', ['data' => $this->data]);
});
}
use with() to send data through session -
public function functionOne() {
$this->data = 'somedata';
return redirect('testingtwo')->with('data', $this->data);
}
Or you could flash() the data for using on next request.
$request->session()->flash('data', $this->data);
the best way for that is
traits
trait Data{
public function getData() {
// .....
}
}
and in your controllers write
use Data;
you can use traits over controllers
or
You can access your controller method like this:
app('App\Http\Controllers\controllerName')->getDataFunction();
This will work, but it's bad in terms of code organisation (remember to use the right namespace for your ControllerName)
I am somewhat new to OOP, although I know about interfaces and abstract classes a bit. I have a lot of resource controllers that are somewhat similar in the bigger scheme of things, they all look like the example below, the only main difference is the index and what I pass to the index view.
What I simply need to know is, can I OO things up a bit with my resource controllers? For example, create one "main" resource controller in which I simply pass the correct instances using an interface for example? I tried playing around with this but I got an error that the interface wasn't instantiable, so I had to bind it. But that means I could only bind an interface to a specific controller.
Any advice, tips and pointers will help me out :)
class NotesController extends Controller
{
public function index()
{
$notes = Note::all();
return view('notes.index', compact('notes'));
}
public function create()
{
return view('notes.create');
}
public function show(Note $note)
{
return view('notes.show', compact('note'));
}
public function edit(Note $note)
{
return view('notes.edit', compact('note'));
}
public function store(Request $request, User $user)
{
$user->getNotes()->create($request->all());
flash()->success('The note has been stored in the database.', 'Note created.');
return Redirect::route('notes.index');
}
public function update(Note $note, Request $request)
{
$note->update($request->all());
flash()->success('The note has been successfully edited.', 'Note edited.');
return Redirect::route('notes.index');
}
public function delete($slug)
{
Note::where('slug', '=', $slug)->delete();
return Redirect::to('notes');
}
}
Note: Totally my opinion!
I would keep them how you have them. It makes them easier to read and understand later. Also will save you time when you need to update one to do something different from the rest. We tried this in a project I worked on and while granted it wasn't the best implementation, it is still a pain point to this day.
Up to you though. I'm sure people have done that in a way that they love and works great. Just hasn't been the case in my experience. I doubt anyone would look at your code though and criticize you for not doing it.
In Case you need to bind different Model instanses then you may use Contextual Binding, for example, put the following code in AppServiceProvider's register() method:
$this->app->when('App\Http\Controllers\MainController')
->needs('Illuminate\Database\Eloquent\Model')
->give(function () {
$path = $this->app->request->path();
$resource = trim($path, '/');
if($pos = strpos($path, '/')) {
$resource = substr($path, 0, $pos);
}
$modelName = studly_case(str_singular($resource));
return app('App\\'.$modelName); // return the appropriate model
});
In your controller, use a __construct method to inject the model like this:
// Put the following at top of the class: use Illuminate\Database\Eloquent\Model;
public function __construct(Model $model)
{
$this->model = $model;
}
Then you may use something like this:
public function index()
{
// Extract this code in a separate method
$array = explode('\\', get_class($this->model));
$view = strtolower(end($array));
// Load the result
$result = $this->model->all();
return view($view.'.index', compact('result'));
}
Hope you got the idea so implement the rest of the methods.
I'm using CakePhp 2.2 and I have this simple controller, named ProvidersController:
<?php
class ProvidersController extends AppController {
public $components = array('Session', 'Social');
public $layout = false;
public function facebook(){
$this->Social->auth('facebook', 'success', 'error');
$this->render(false);
}
public function google(){
$this->Social->auth('google', 'success', 'error');
$this->render(false);
}
private function success(){
}
private function error(){
}
}
?>
and this Component, named SocialComponent:
<?php
class SocialComponent extends Component {
public function auth($provider, $success, $error){
}
}
?>
as you can see I have created success() and error() methods inside the controller. Now I pass these names and I would like to call them back from the component.
I only pass the name of the callback, how to call them from the component?
Thank you!
Have a look at the source code of the SecurityComponent in CakePHP, it has an identical situation with its blackHoleCallback.
They use a helper function SecurityComponent::_callback() which uses PHP's call_user_func_array()
protected function _callback(Controller $controller, $method, $params = array()) {
if (is_callable(array($controller, $method))) {
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
} else {
return null;
}
}
You can use the same pattern to pass callbacks into your component.
The point of a component is re-usability across many controllers - if you're trying to make it access a specific controller function, you should probably just be using controller methods, not a component.
BUT - you can always just do your logic in the component and pass back data (upon success or error), then check the results in the controller, and access whichever method you'd like based on those results.
Since your 'success' or 'error' logic is in the controller, I assume you don't want it in the component... ie it's different per use of the component. In that case, all you really want the component to do is do the logic and let you know how it went (return data).
//Controller
//..
public function facebook(){
$results = $this->Social->auth('facebook', 'success', 'error');
if($results['error']) $this->Social->error();
$this->render(false);
}
private function success(){ }
private function error(){ }
//...
//Component
//...
public function auth($provider, $success, $error){
$results = array();
//do something
$results['error'] = true;
return $results;
}
//...