Atm I'm creating this view composer for fun. It is collecting .js filenames and then passing it to the layout to be linked. The filenames used depend on the current page. For example a lower ranked page like Slides, doesn't include ajax requests used in UserManagement. Please don't ask me why I would do this xD. Im planning to validate requests anyway. Just being bored.
Anyways, as I'm quite new to laravel I'm still looking for more efficient ways to do things.
Atm Im accessing the file names staticly. The Controller now looks like this
class Controller extends BaseController
{
public static $js_file_names = [];
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
In the pagecontroller I construct the filenames:
class SlidesController extends Controller
{
public function __construct()
{
parent::$js_file_names = ['ccs', 'ajax-updates'];
}
And finaly I retreive them inside the registered Viewcomposer like this:
(during development $use_filenames has all files as default)
public function __construct()
{
$filenames = Controller::$js_file_names;
if( !empty($filenames) )
$this->use_filenames = $filenames;
var_dump($this->use_filenames);die;
}
It all seems to be working fine, but the big question is, is there a better way to access controller data from inside a viewcomposer? Every time I try to google this, I get results like 'passing data to views' etc, which is not rly the problem.
Update:
Another idea I had is to store all the filenames to be used in an array inside the viewcomposer itself, and check if the current page exists in that array. This would keep the controllers cleaner.
Using a view composer doesn't really make sense in this situation. Since your controllers already 'know' which files they intent to share, you may as well just pass them to the view like so:
class SlidesController extends Controller
{
public function __construct()
{
View::share('user_filenames', ['ccs', 'ajax-updates']);
}
}
A composer is more for sharing concrete elements such as collections of users, a service provider or some other class instance, for example.
Related
I have one FrontendController that get all requests from frontend. As all URLs are like:
Route::get('/{slug}', 'FrontendController#index');
I need to use the same controller to get all Entities. My FrontendController looks like this:
use Auth;
use App;
use Cache;
use URL;
use Redirect;
use Session;
use Response;
use App\Country;
use App\I18n;
use App\User;
use App\CMS;
use App\CMSPageContent;
use App\Slugs;
use App\News;
...
...
use App\Http\Controllers\Controller;
I have several questions regarding this:
Are ALL these services injected in each execution of FrontendController. Because maybe I'm loading the entire code and It will make my page load slow.
If answer to previous question is yes, can I load a library only if one function is called?
Is it a good way to solve the slug problem? Because all URLs have one piece only for SEO reasons and I don't know other way to treat the routes.
It varies depending on how you are using the code. For example if you required the Auth login method, but nothing else, it would be a waste of resources to initialise a model or inject the model into that function.
For example say this is a function in my model
public function doSomething()
{
//Do stuff
}
I would like to call this function in my Controller. I have a few options, I could reference the model at the top of my controller
use App\MyModel;
I believe this doesn't actually initiate the model, it acts like a reference, so that when it is called, the system knows where to find it.
I could inject it into my function
public function myControllerFunction(\App\MyModel $model)
{
return $model->doSomething();
}
This uses the most resources due to the model being assigned to the $model variable, which is fine if you need the models eloquent for database actions and its functions. If you require just one function from that model then a static call would use less resources.
In your model make the function static
public static function doSomething()
{
}
Then in your controller you can call it like this
public function myControllerFunction()
{
return \App\MyModel::doSomething();
}
This would use the less resources and would clean up the code a bit as you wouldn't need to keep referencing your uses at the top of the controller
Take a look to that code
<?php
namespace Sestante\SestanteBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Sestante\SestanteBundle\Model\StrutturaManager;
class MainController extends Controller
{
public function indexAction(Request $request)
{
return $this->render('SestanteSestanteBundle:Main:index.html.twig');
}
public function showLodgingsAction(Request $request)
{
$repo = $this->getDoctrine()->getRepository('SestanteSestanteBundle:Struttura');
$usr = $this->get('security.context')->getToken()->getUser();
$usrId = $usr->getId();
$sm = new StrutturaManager($repo);
$lodgingList = $sm->retrieveLodgingsFromUser($usrId);
return $this->render('SestanteSestanteBundle:Main:showLodgings.html.twig',array('lodgingList' => $lodgingList));
}
}
This is a controller for an application that I've been writing.
Take a look to showLodgingsAction. I've tryied to place all business logic into a model (StrutturaManager) that with a repository (that I've passed directly from controller because, as far I know, they're available only here or via D.I.) query my db, do some elaboration and return a list that I'll render onto a template.
First question: Is this "code separation" good, or exists a better way for do what I'm trying to do?
Second question: suppose that, now, I want to use an object of StrutturaManager type into indexAction. Remember that mine object want a repository. So, have I to declare again, and again, and again, all my object for every controller's action where I want to use them? I suppose that must exist a smarter method but, at the moment, I don't understand which.
Define StrutturaManager as a service and inject the EntityManager into it. This way the manager will have access to repositories you need and controllers won't know about Doctrine nor repositories — which is a good practice.
I'm having Codeigniter object scope confusion.
Say I load a model in a controller:
$this->load->model('A');
$this->A->loadUser(123); // loads user with ID 123
// output of $this->A now shows user 123
$this->load->model('B');
$this->B->examineUser ();
// output of $this->A now shows user 345
class B extends Model
{
public function examineUser ()
{
$this->load->model('A');
$this->A->loadUser(345); // loads user with ID 345
}
}
I would have thought that $this->A would be different from $this->B->A but they are not. What is the best solution to this issue? It appears the ->load->model('A') in the examineUser () method does nothing because it was loaded in the controller. Then the call to loadUser () inside that method overwrites the stored properties of $this->A. This seems like a bugfest waiting to happen. If I needed global models, I would have use static classes. What I wanted was something scoped pretty much locally to the model object I was in.
Is there a way I can accomplish this but not go way outside of CI's normal way of operating?
Followup/related:
Where do most people put there "->load->model" calls? All at the beginning of a controller action? I figured it would be easier -- though perhaps not excellent programming from a dependency injection perspective -- to load them in the model itself (construct or each method).
Whenever you use the Loader Class ($this->load->), it will load the object into the main CI object. The CI object is the one you keep referring to as $this->. What you've done is load model A twice into the CI object.
Essentially, all object loaded using the Loader class goes into a single global scope. If you need two of the same type, give them different names, as per $this->load->model('A','C'). I don't know of any way around it unless you revert to using bog-standard PHP.
In my team's code, we generally load the models in the controller's constructor, then load the data to send to the view in the function, often _remap().
This is not how the loader works sadly. CodeIgniter implements a singleton pattern, which will check to see if the class is included, instantiated and set to $this->A then will be ignored if loaded again. Even if you are inside a model, $this->A will be referenced to the super-instance via the __get() in class Model. Alis it, or just do:
class B extends Model
{
public function examineUser ()
{
$user = new A;
$user->loadUser(345); // loads user with ID 345
}
}
Here's what I've decided to do, please comment if you have advice:
I've extended the CI Loader class:
<?php
class SSR_Loader extends CI_Loader
{
function __construct()
{
parent::__construct ();
}
/**
* Model Retriever
*
* Written by handerson#executiveboard.com to create and return a model instead of putting it into global $this
*
* Based on original 2.0.2 CI_Loader::model ()
*
*/
function get_model($model)
{
if (empty ($model))
{
return;
}
$name = basename ($model);
if (!in_array($name, $this->_ci_models, TRUE))
{
$this->model ($model);
}
$name = ucfirst($name);
return new $name ();
}
}
Do any CI guru's see a problem with that before I invest time in changing my code a bit to accept the return obj, ala:
// in a controller:
public function test ($user_id=null)
{
$this->_logged_in_user = $this->load->get_model ('/db/users');
$this->_viewed_user = $this->load->get_model ('/db/users');
$this->_logged_in_user->load($this->session->userdata ('user.id'));
$this->_viewed_user->load($user_id);
}
I could also do private $_logged_in_user to make it available in the controller but positively force it to be limited to just the current controller and not spill anywhere else, or I could just do $_logged_in_user = $this->load->get_model ('/db/users'); and limit it to just the current method, which is probably what I'll do more often.
This seems like a pretty straightforward way to "fix" this issue (I say "fix" b/c it's not really a bug, just a way of doing things that I think is a bad idea). Anyone see any flaws?
I have a simple logic problem. I'm starting on use CodeIgniter and I'm understand the Controller concept now. The view, for instance, is used only to generate content (not pre-proccess data), controller to get all infos need to view. Fine.
My problem is: I have a poll that is called as /poll/1 from an iframe, and I like to print it in other moment on another controller. This path is relatives to Poll::index(1) (logically talking) and I'm on Content::index().
I don't found explanation for cases like that on the CI UserGuide.
How I do?
Thanks.
Edit: I'll do an example code:
class Blog extends CI_Controller {
function index(){
// Do some prints
// Executes Poll::index(1), but store on some string
// Do some prints
}
}
class Poll extends CI_Controller {
function index($id){
// Do some prints
}
}
The idea is that: /poll/1 works and /blog too (but this second will print more content, with the poll).
hummm interesting i think using ob_start() might just work for you, if it was me i would rather use a ajax call to display poll data
here is the code.
class Blog extends CI_Controller {
function index(){
// Do some prints
// Executes Poll::index(1), but store on some string
ob_start();
Poll::index(1)
// You can now use this $output value to display or store in db or store in session,
// but remember CI session can only hold upto certain length as it uses cookie
$output = ob_get_contents();
ob_end_clean();
// Do some prints
}
}
class Poll extends CI_Controller {
function index($id){
// Do some prints
}
}
One way which is my favorite is use one as a super class so class Poll extends blog. This allows your poll to take advantage of your blog methods. Then you can use any parent methods and load the proper views in which ever class#method you want.
Let's say that I have a website that has 100 different pages. Each page uses a common header and footer. Inside the header is some dynamic content that comes from a database.
I'd like to avoid having to have code in every single controller and action that passes this common code into the view.
function index()
{
// It sucks to have to include this on every controller action.
data['title'] = "This is the index page";
data['currentUserName'] = "John Smith";
$this->load->view("main_view", data);
}
function comments()
{
// It sucks to have to include this on every controller action.
data['title'] = "Comment list";
data['currentUserName'] = "John Smith";
$this->load->view("comment_view", data);
}
I realize that I could refactor the code so that the common parts are in a single function and the function is called by the action. Doing so would reduce SOME of the pain, but it still doesn't feel right since I'd still have to make a call to that function every time.
What's the correct way to handle this?
One way I have been doing this is to extend the default controller class. You can read up on extending classes with MY_Controller in the user guide. Inside this extended class you can include something that you ALWAYS want to do, like render the page header template before the main content, or authorise a users access etc.
class MY_Controller extends Controller {
function __construct()
{
parent::Controller();
//code to always do goes here
echo 'Always print this comment';
$this->load->view('partials/template_start');
}
}
Then you can have your normal controller class extend THIS class by using
class MyControllerNameHere extends MY_Controller {
function __construct()
{
//setup here
}
function index()
{
echo 'Only print this bit when this method is called';
$this->load->view('partials/MYPAGENAMEHERE');
}
}
There are other ways of doing this, I use a mixture of the above and William's Concepts Codeigniter Template library. Do a bit of searching - there are a few solutions for you.
I had a similar situation. I created an 'includes' folder, and in there put a file that had the repetitive code from my controllers. Then in the controllers just include('/path/to/includeFile.php');
Don't know if it's the "correct" way, but it works well for me.
I ran across this after a search of their site. http://codeigniter.com/wiki/Header_and_footer_and_menu_on_every_page/ I'll review this page and its links, then post my thoughts.