I'm upgrading my app from ZF-1.12 to ZF-2.4.
I' have this login controller:
class LoginController extends AbstractActionController {
public function indexAction() {
$this->layout('login/layout');
return new ViewModel(array(
'form' => 'some-form-object',
));
}
}
The thing is, the view seems to be rendered without the selected layout.
However, when I comment out the 'return new ViewModel'.. everything works as expected.
What am I doing wrong?
Many thanks.
Apparently 'form' is sensitive word, when changing the var name - it worked.
Related
Disclaimer: I'm new to ASP.NET Core / Razor / MVC and am starting out on the 3.0 preview.
What I want to do is have a "button" on my page that adds a new empty item to a list so that the user can input some values. From what I've read (which is quite a bit) it sounds like having a hyperlink point towards a controller is the right approach to this. I cannot get it to actually work though. Here's my code:
Link pointing to controller / action:
<a class="btn btn-success" asp-controller="Customer" asp-action="AddProduct">New Product</a>
Controller:
public class CustomerController : Controller
{
public void AddProduct()
{
var tmp = "";
}
public string Index()
{
return "This is my default action...";
}
public string Welcome()
{
return "This is the Welcome action method...";
}
}
Startup.cs routing is default:
app.UseRouting(routes =>
{
routes.MapRazorPages();
});
With this setup, if I click the start button, I see the URL change to the below, but nothing else happens (no break point is hit, for example):
https://localhost:44358/Customers/Create?action=AddProduct&controller=Customer
I have tried to adding the route to specifically to the UseRouting code, like such:
app.UseRouting(routes =>
{
routes.MapRazorPages();
routes.MapControllerRoute(
name: "Customer",
template: "{controller=Customer}/{action=Welcome}");
});
But when I do this, it seems to break, as the text color changes (from white to black) and nothing happens when I click it.
Any idea on where I'm going wrong?
I do have one more question - which is how do you access the model data from the controller?
See middle of page here: https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-core-3-0-preview-4/
In Startup.cs Configure:
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapRazorPages();
routes.MapFallbackToPage("/Home");
});
Hello I am having some difficulty setting up a RESTful routing for a login controller. I keep getting hit with a status 404. Here is what I have so far. Any ideas?
In my routes:
'login' => array(
array('GET', new Route('session/login')),
array('POST', new Route('session/login'))
),
And in my sessions controller I have:
class Controller_Session extends Controller_Template {
public function get_login(){
return View::forge('session/login');
}
public function post_login() {
return View::forge('session/login',$data);
}
}
Try it using the default routing and the Rest controller.
class Controller_Session extends Controller_Rest
{...}
Delete the routes you set up and try accessing the Controller using {url}/session/login
basically delete all routes you have created.
Then create a controller session.php:
class Controller_Session extends Controller_Rest
//class Controller_Session extends Controller_Hybrid
{
public function get_login()
{
return View::forge('session/login');
}
public function post_login()
{
return View::forge('session/login',$data);
}
}
You can extend Controller_Hybrid, if you want to access to both rest and non-rest methods.
Now try with jquery to access url: '/session/login'
It should work!
Good luck
It was an Apache error. The mod rewrite module was not activated on a Debian Based OS
I'm just starting out developing for Zend Framework 2. I'm trying to add a simple menu to my Application. The menu will eventually be loaded from a database as user-definable bookmarks, so at the moment, I am trying to instantiate a view helper I've defined, add pages programmatically in the controller, and then inject the view helper's navigation into the view model. My problem is that when I try to retrieve my view helper in the controller by using the ServiceLocator, I get a ServiceNotFoundException:
Application\View\Helper\ShortcutsMenu:
namespace Application\View\Helper;
use Zend\Navigation\Navigation;
class ShortcutsMenu extends Navigation {
public function shortcutsMenu() {
//...
}
public function __construct() {
//...
}
}
and in Module.php
public function getServiceConfig() {
return array(
'view_helper' => array(
'factories' => array(
'shortcutsmenu' => function($sm) {
$smenu = new \Application\View\Helper\ShortcutsMenu();
return $smenu;
}
),
),
);
IndexController.php:
$smenu = $this->getServiceLocator()->get('shortcutsmenu'); // throws ServiceNotFoundException
//"Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for shortcutsmenu"
$smenu->addPage(AbstractPage::factory(array(
'label' => 'Homepage',
'order' => '-1',
'uri' => '/',
)));
// ...
}
Can anyone tell me what I'm missing?
Edit:
The HTML I would like to generate in the application-wide layout would be something like:
<!-- Side tabs shortcuts -->
<ul id="shortcuts">
<li class="current">Home</li>
<li>My messages</li>
<li>Bob's calendar</li>
<li>...</li>
</ul>
probably using URI-style links rather than MVC ones.
There is no need to extend the navigation container Zend\Navigation\Navigation or extend the builtin view helpers to render menu's.
A container manages all pages in the navigation structure. The are several ways to create a container.
All the view helpers (menu, breadcrumbs) use the container as the provider for navigation data. You can eighter set a new container on the view helper using setContainer(). Alternatively you could just call the view helper in your view without a container setup and the view helper will create a new empty container for you.
If you need some alternate rendering because the default view helpers don't provide it you can create you own navigation view helper.
namespace MyNamespace\View\Helper\Navigation;
use Zend\View\Helper\Navigation\AbstractHelper;
class MyHelper extends AbstractHelper
{
}
Next register your view helper to the navigation pluginManager. I think you can do something like this (untested):
class Module
{
public function onBootstrap($e)
{
$application = $e->getApplication();
/** #var $serviceManager \Zend\ServiceManager\ServiceManager */
$serviceManager = $application->getServiceManager();
$pm = $serviceManager->get('ViewHelperManager')->get('Navigation')->getPluginManager();
$pm->setInvokableClass('myHelper', 'MyNamespace\View\Helper\Navigation\MyHelper');
}
}
Now call you custom helper in your view:
$this->navigation()->myHelper()
I'm quite new to zf2 and I'm experimenting with it. I have a view helper and I need it to access a table object. In my controller I can run:
$this->getServiceLocator();
But ideally I would run this inside my view helper. Unfortunately, I can't seem to access it from within my view helper. I tried passing it through the constructor, configuring a factory method in module.config.php, but when I try that, Zend will no longer pass a tablegateway object into one of my model objects created from a service factory method in the module's Module.php file. This seems to be because it no longer calls the factory method, and opts to run instantiate without any parameters.
I'm not certain I understand why the view factory methods would affect a different set of factory methods with different names.
Can anyone tell me what is wrong with what I'm doing? I can provide more details, but at this point I'm unclear on what details are actually important without supplying the entire codebase.
Thanks.
Crisp does provide a valid answer to your question, but I would suggest to take it one step further. The injection of the service locator makes your view helper tightly coupled to the framework and service locator pattern and vulnerable because every piece of code inside your application can modify every service in the service locator.
There are reasons to inject your dependency directly, so you only depend on your dependencies and you're not implementing this anti-pattern anymore. Let's assume your view helper depends on MyModule\Model\MyTable, then the constructor of your view helper would just look like this:
namespace MyModule;
use MyModule\Model\MyTable;
use Zend\View\Helper\AbstractHelper;
class MyViewHelper extends AbstractHelper
{
protected $table;
public function __construct(MyTable $table)
{
$this->table = $table;
}
}
As you pointed out, you just inject your MyTable now:
namespace MyModule;
class Module
{
public function getViewHelperConfig()
{
return array(
'factories' => array(
'MyViewHelper' => function($sm) {
$sm = $sm->getServiceLocator(); // $sm was the view helper's locator
$table = $sm->get('MyModule_MyTable');
$helper = new MyModule\View\Helper\MyHelper($table);
return $helper;
}
)
);
}
}
Note that inside a view helper factory your service manager is the view helper's service manager and not the "main" one where the table is registered (see also a blog post of I wrote earlier). The $sm->getServiceLocator() solves this for you.
I'm not certain I understand why the view factory methods would affect a different set of factory methods with different names.
It's not, so there is probably a bug in your code. If above does not work, please provide some more details on your service manager configuration so I can update my answer.
One of the great advantages of above approach is you make unit testing really easy for your view helper. You can mock the table gateway and focus on the complete behaviour of your view helper.
use MyModule\View\Helper\MyHelper;
public function testHelperusesTable
{
$mock = $this->getMock('MyModule\Model\MyTable');
$helper = new MyHelper($mock);
// Test your $helper now
}
You can inject the service locator into your view helper from the view helper config in Module.php
// Application/Module.php
public function getViewHelperConfig()
{
return array(
'factories' => array(
'myViewHelper' => function ($serviceManager) {
// Get the service locator
$serviceLocator = $serviceManager->getServiceLocator();
// pass it to your helper
return new \Application\View\Helper\MyViewHelper($serviceLocator);
}
)
);
}
In your view helper
<?php
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper,
Zend\ServiceManager\ServiceLocatorInterface as ServiceLocator;
class MyViewHelper extends AbstractHelper
{
protected $serviceLocator;
public function __construct(ServiceLocator $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
}
While working in Zend Framework,we often need custom helper,that make our work easy, In zf1 accessing database model from helper was easy,but i got stuck that how to access database model for any table in Custom View Helper, but as i was needing it i get around through the problem in unprofessional way by creatina new db adapter object in the view, which was never good way, but recently i came to know through very interesting way to access the database adapter in the view helper and there i have to execute any query on any table, it may be not so Zend F2 way, but very simple and short way to solve the issue.
Here is my Model Example...
<?php
namespace Application\Model;
use Zend\Db\TableGateway\TableGateway;
class SlideImageSubTable {
protected $tableGateway;
public $adapter;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
$this->adapter = $this->tableGateway->getAdapter();
}
public function fetchAll() {
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function getSlideImageSub($id) {
$id = (int) $id;
$rowset = $this->tableGateway->select(array('id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
public function getImageMenu($id) {
$id = (int) $id;
$rowset = $this->tableGateway->select(array('slide_image_id' => $id));
$rows = array_values(iterator_to_array($rowset));
if (!$rows) {
throw new \Exception("Could not find row $id");
}
return $rows;
}
public function saveSlideImageSub(SlideImageSub $slideImageSub) {
$data = array(
'slide_image_id' => $slideImageSub->slide_image_id,
'title' => $slideImageSub->title,
'description' => $slideImageSub->description
);
$id = (int) $slideImageSub->id;
if ($id == 0) {
$this->tableGateway->insert($data);
} else {
if ($this->getSlideImageSub($id)) {
$this->tableGateway->update($data, array('id' => $id));
} else {
throw new \Exception('Form id does not exist');
}
}
}
public function deleteSlideImageSub($id) {
$this->tableGateway->delete(array('id' => $id));
}
}
Just look at the 'public $adapter' public variable. And in the constructor i am going to initialize it by calling $this->tableGateway->getAdapter(); method, getAdapter() is available thorugh gateway object.
Then in my controller action view, i have to assign it to any variable and pass that variable to view page. like this..
public function equitiesAction() {
$image_id = $this->params('id');
$result = $this->getTable('SlideImageSub')->getImageMenu($image_id);
$adapter = $this->table->adapter;
$view = new ViewModel(array(
'result' => $result,
'adapter' => $adapter,
));
return $view;
}
And in the view i pass the 'adapter' object to custom view like this..
<?php echo $this->GetMenuProducts( $this->adapter); ?>
Now in custom view i can use this database adapter object and create select query on any table.
Hope this will help someone, i look around for using database access in custom view helper but the configurations methods provided was not working for me.
Thanks
$this->getView()->getHelperPluginManager()->getServiceLocator();
I'm in the day 10 of Symfony's Jobeet Tutorial. Everything worked good, but when I tried to go to the index page: http://localhost:9090/frontend_dev.php
I got the following message:
sfPatternRouting Match route "job" (/job.:sf_format) for /job with parameters array ( 'module' => 'job', 'action' => 'index', 'sf_format' => 'html',)
2 Info sfFrontWebController Action "job/index" does not exist
3 Error sfError404Exception Action "job/index" does not exist.
(I still have a backup of day 9, and the index page works fine).
Any suggestions?
I guess you have replaced the methods in app/modules/job/actions.class.php with what you found on day 10, instead of simply adding them. There must be an executeIndex() method in this file if you want to get something in /job
Yeah, it's something like this:
class jobActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
$this->categories = Doctrine_Core::getTable('JobeetCategory')->getWithJobs();
}
public function executeShow(sfWebRequest $request)
{
$this->job = $this->getRoute()->getObject();
}
public function executeNew(sfWebRequest $request)
{
...
}
...
}
I also had overwrite it. Yeah so executeIndex and executeShow are important for "index" and "show". ;)