Silex passing app and request to controller classes - silex

I want a simple way to access $app and $request in my controller classes. The document says to do this,
public function action(Application $app, Request $request) {
// Do something.
}
but it doesn't look right to have to inject $app and $request to every method. Is there a way to include $app and $request to every controller by default, maybe using the constructor? I'd like to be able to use it as $this->app.
Thanks.

In the Controllers as Services part of the documentation you can see how to inject dependencies to controller classes via the constructor - in that case a repository.

It's possible :
Create a ControllerResolver.php somewhere in your project and put this inside :
namespace MyProject;
use Silex\ControllerResolver as BaseControllerResolver;
class ControllerResolver extends BaseControllerResolver
{
protected function instantiateController($class)
{
return new $class($this->app);
}
}
Then register it in your app (before $app->run();):
$app['resolver'] = function ($app) {
return new \MyProject\ControllerResolver($app, $app['logger']);
};
Now you can create a base controller for your app, for example :
namespace MyProject;
use Silex\Application;
use Symfony\Component\HttpFoundation\Response;
abstract class BaseController
{
public $app;
public function __construct(Application $app)
{
$this->app = $app;
}
public function getParam($key)
{
$postParams = $this->app['request_stack']->getCurrentRequest()->request->all();
$getParams = $this->app['request_stack']->getCurrentRequest()->query->all();
if (isset($postParams[$key])) {
return $postParams[$key];
} elseif (isset($getParams[$key])) {
return $getParams[$key];
} else {
return null;
}
}
public function render($view, array $parameters = array())
{
$response = new Response();
return $response->setContent($this->app['twig']->render($view, $parameters));
}
}
And extend it :
class HomeController extends BaseController
{
public function indexAction()
{
// now you can use $this->app
return $this->render('home.html.twig');
}
}

Related

Unity how to pass Request in Controller's constructor from Unity

The old controller code with Concrete dependencies:
public SomeController: Controller
{
public SomeController()
{
}
public ActionResult Default()
{
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
}
}
The new Controller code with TDD focus:
public SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomething something)
{
_something = something;
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
PROBLEM:
Now in new TDD approach i need to invoke constructor where I am registering the Interface. I have put it in UnityBootstraper common file, Something like:
var container = new UnityContainer();
container.RegisterType();
**Something something = new Something(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());**
something.SomeMethod();
This is not working here. Error is quite clear:
Object reference required for non-static field, method, property 'System.Web.Mvc.Controller.Request.get'.
I can't figure out how i can access http request here in UnityBootstrapper?
Edit:
Trying to do all this in RegisterRoutes.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(UnityBootstrapper.Initialise()));
var container = new UnityContainer();
container.RegisterType<ISometing, Something>();
}
}
One way to do it is to create an abstract factory like this:
public interface ISomethingFactory
{
ISomething Create(string url);
}
public class SomethingFactory : ISomethingFactory
{
public ISomething Create(string url)
{
return new Something(url);
}
}
And make your controller depend on it like this:
public class SomeControllerNew: Controller
{
private readonly ISomething _something;
public SomeControllerNew(ISomethingFactory somethingFactory)
{
_something = somethingFactory.Create(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString();
}
public ActionResult Default()
{
_something.SomeMethod();
}
}
A better approach (IMO) is to use a custom Controller Factory instead of using the Dependency Resolver like this:
public class CustomFactory : DefaultControllerFactory
{
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var request = requestContext.HttpContext.Request; //Here we have access to the request
if (controllerName == "Some") //Name of controller
{
//Use the container to resolve and return the controller.
//When you resolve, you can use ParameterOverride to specify the value of the string dependency that you need to inject into Something
}
return base.CreateController(requestContext, controllerName);
}
}
This way you don't have to introduce the ISomethingFactory, and your controller would still depend on ISomething directly.
You would need to tell the MVC framework about this custom controller factory like this (in Application_Start):
ControllerBuilder.Current.SetControllerFactory(new CustomFactory());

ZF2 TableGateway join

I am in the process of trying to learn OO/Zend Framework over standard PHP.. I want to scream and write a mysql query instead of using the TableGateway method.
I have been following tutorials and have successfully printed out a table and some fields, although with the way I have gone about doing this, I am totally lost in how I should make this a join with another table and print out some fields there.
For example.
Table Fields
customer Idx, Company
contact Idx, First_Name
This is my customersController where I assume the work is carried out
namespace Customers\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\DB\TableGateway\TableGateway;
class CustomersController extends AbstractActionController
{
protected $customersTable;
public function indexAction()
{
return new ViewModel(array('customer' => $this->getCustomersTable()->select()));
//return new ViewModel(array('customers' => $this->fetchJoin()->select()));
}
public function addAction()
{
}
public function editAction()
{
}
public function deleteAction()
{
}
public function getCustomersTable()
{
if (!$this->customersTable) {
$this->customersTable = new TableGateway (
'customer', //table name
$this->getServiceLocator()->get('Zend\DB\Adapter\Adapter')
);
}
return $this->customersTable;
}
}
Am I on the right track here?
If you need to make joins read about Zend\Db\Sql and Zend\Db\Select
which you can read about here
http://framework.zend.com/manual/2.0/en/modules/zend.db.sql.html
An example would be:
In your model(that extends the TableGateway or the AbstractTableGateway)
in Some function you can have something like(this is from a project) :
$sql = new \Zend\Db\Sql\Sql($this->getAdapter());
$select = $sql->select()
->from('event_related_events')
->columns(array())
->join('event_invitees', 'event_invitees.event_id =
event_related_events.related_event_id')
->where(array('event_related_events.event_id' => $eventId));
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $this->getAdapter()->query($selectString, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
Then you can loop over the results and do what you need to.
Taking a look at more powerful ORM like Doctrine or Propel may also help, but may be an overkill for a small/hobby project.
EDIT: Answer for what was asked in comments
For Using expression(if, case etc) directly you can use something like :
$sql->select()
->from('table')
->columns(array(
'sorter' => new Expression('(IF ( table.`something` >= 'otherthing', 1, 0))'),
'some_count' => new Expression('(count(*))'),
)
)
Explaining the last line in SQL terms, it would be:
count(*) AS some_count
So this is my controller, basically from the Album example but now it will display customers from the customer table.
<?php
namespace Customers\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Customers\Model\Customers;
use Customers\Form\CustomersForm;
class CustomersController extends AbstractActionController
{
protected $customersTable;
public function indexAction()
{
return new ViewModel(array(
'customer' => $this->getCustomersTable()->fetchAll(),
));
}
public function addAction()
{
}
public function editAction()
{
}
public function deleteAction()
{
}
public function getCustomersTable()
{
if (!$this->customersTable) {
$sm = $this->getServiceLocator();
$this->customersTable = $sm->get('Customers\Model\CustomersTable');
}
return $this->customersTable;
}
}
?>
The indexAction calls the getCustomersTable method which goes to the model (CustomersTable) and executes the "query" there.
<?php
namespace Customers\Model;
use Zend\Db\TableGateway\TableGateway;
class CustomersTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function getCustomers($id)
{
}
public function saveCustomers(customers $customers)
{
}
public function deleteCustomers($id)
{
}
}
?>
So from your example, I should be trying to implement this into the fetchAll in the model?
Thanks for the help.
$sql = new \Zend\Db\Sql\Sql($this->getAdapter());
$select = $sql->select()
->from('customer')
->columns(array())
->join('contact', 'contact.Idx = customer.Idx')
->where(array('contact.Idx' => $eventId));
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $this->getAdapter()->query($selectString, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);

How to use translate method in view helper?

Let say that we have example view helper code like this:
namespace Product\View\Helper;
use Zend\View\Helper\AbstractHelper;
class ProductType extends AbstractHelper
{
public function __invoke($id)
{
return $this->translate('Super extra product'); # How to use this method here
}
}
Now what it the best way to use translate in this view helper?
Regards,
The easiest way is translate view helper:
public function __invoke($id)
{
return $this->view->translate('Super extra product');
}
Also you can use ServiceManager to do translate or other actions.
In your Module.php change getViewHelperConfig to pass ServiceManager:
public function getViewHelperConfig()
{
return array(
'factories'=>array(
'ProductType'=>function ($helperPluginManager){
return new \Product\View\Helper\ProductType($helperPluginManager->getServiceLocator());
}
)
);
}
Now, you can use ServiceManager to translate in view helper:
class ProductType extends AbstractHelper
{
protected $serviceManager;
public function __construct($serviceManager)
{
$this->serviceManager = $serviceManager;
}
public function __invoke($id)
{
return $this->serviceManager->get('translator')->translate('Super extra product');
}
}

Windsor container components not available on first controller action

I'm using a configuration within the global.asax.cs to register the components but it looks the container hasn't been initialized yet at the first http request (HomeController > Index action) and it gives me a "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection." error.
I can't find a solution for this and is driving me mad!
Extract of my global.asax.cs:
protected void Application_Start()
{
InitializeContainer();
InitializeDatabase();
RegisterRoutes(RouteTable.Routes);
}
private void InitializeContainer()
{
_container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container));
// Register context manager.
_container.Register(
Component.For<IContextManager>()
.ImplementedBy<CoursesContextManager>()
.LifeStyle.Singleton
.Parameters(
Parameter.ForKey("connectionString").Eq(ConfigurationManager.ConnectionStrings["CoursesConnection"].ConnectionString)
)
);
// Register specifc repository implementations (can we do this more generic?)
_container.Register(
Component.For<ICourseRepository>()
.ImplementedBy<CourseRepository>()
.LifeStyle.Singleton
);
[...other interfaces and controllers registered...]
}
Controller where the exception is thrown at first http request:
public class HomeController : Controller
{
private ICourseRepository _courseRepository;
public HomeController(ICourseRepository courseRepository)
{
_courseRepository = courseRepository;
}
public ActionResult Index()
{
var courses = _courseRepository.Find(); //here is where it fails
return View(courses);
}
}
Repository/interfaces:
Generic interface:
public interface IRepository<T>
{
IQueryable<T> Find();
}
Generic repository:
public class MyRepository<T> : IRepository<T> where T : class
{
private IContextManager _contextManager;
private string _qualifiedEntitySetName;
private string _keyName;
protected ObjectContext CurrentObjectContext
{
get { return _contextManager.GetContext(); }
}
protected ObjectSet<T> ObjectSet
{
get { return CurrentObjectContext.CreateObjectSet<T>(); }
}
public MyRepository(IContextManager contextManager)
{
this._contextManager = contextManager;
this._qualifiedEntitySetName = string.Format("{0}.{1}"
, this.ObjectSet.EntitySet.EntityContainer.Name
, this.ObjectSet.EntitySet.Name);
this._keyName = this.ObjectSet.EntitySet.ElementType.KeyMembers.Single().Name;
}
public IQueryable<T> Find()
{
return ObjectSet;
}
}
Interface course based on generic repository:
public interface ICourseRepository : IRepository<Course>
{
}
if you use Unit Of Work pattern you will solve your problem
Check this post Unit Of Work Pattern, is very usefull
I found a way to handle with this at least momentarily. Because the problem happens on the first request, I've just added another action in my controller and redirect the index action to it. Probably not the best solution but can't spend more time on this issue!
public class HomeController : Controller
{
private ICourseRepository _courseRepository;
public HomeController(ICourseRepository courseRepository)
{
_courseRepository = courseRepository;
}
public ActionResult Index() // Default action in the controller, first hit
{
return RedirectToAction("Home");
}
public ActionResult Home() //The repository is available here, no exception thrown
{
var courses = _courseRepository.Find(); //here is where it fails
return View(courses);
}
}

Inline Interface implementation in Actionscript

Is something like this possible in Actionscript?
Java:
URLFetcherFactory.setCreator(
new IURLFetcherCreator() {
public IURLFetcher create() {
return new URLFetcher();
}
}
);
Actionscript:
?
I've been wondering about this and have been unable to find anything that indicates it's possible. Figured if it was possible, I'd be able to find an answer here. Thanks! Stackoverflow rocks!
You cannot create an instance of an interface. You can, however, create a factory class:
public class URLFetcherCreator : IURLFetcherCreator {
private var _cls : Class;
public URLFetcherCreator(Class cls) {
this._cls = cls;
}
public function create() : IURLFetcher
{
return new cls();
}
}
Alternatively, change setCreator to accept a Function that returns an IURLFetcher:
URLFetcherFactory.setCreator(
function() : IURLFetcher {
return new URLFetcher();
}
);
Try this:
URLFetcherFactory.setCreator(
new IURLFetcherCreator() {
public function create():IURLFetcher {
return new URLFetcher();
}
}
);
You can't use anonymous inner classes in AS3.
For special cases like callbacks you can use Function instead of anonymous inner classes.
Java:
interface Callback {
void done(String info);
}
class Service {
void process(Callback callback);
}
...
myService.process(new Callback() {
void done(String info) {
// trace(info);
}
}
AS3:
class Service {
public function process(callback:Function):void;
}
...
myService.process(function(info:String):void {
trace(info);
});

Resources