I'd like to access the basePath view helper inside my Application Module Bootstrap.
Here's the current code in my Application Module:
public function onBootstrap(MvcEvent $e)
{
$viewHelperManager = $e->getApplication()->getServiceManager()->get('viewhelpermanager');
$basePath = $viewHelperManager->get('BasePath');
$headScript = $viewHelperManager->get('HeadScript');
$headScript->appendFile($basePath->basePath('/js/custom.js'));
}
I'm able to get the head script view helper to add the javascript but i cannot get access to the base path view helper
If you look at the code, the call is: $basePath->basePath('/js/custom.js').
How do I accomplish this?
Any help would be appreciated.
There's nothing wrong with the way you were fetching the helper in your question, the only problem is the way you're trying to call the helper method.
The BasePath view helper is an invokable class, you can either call its __invoke() method explicitly
$basePath = $viewHelperManager->get('BasePath');
$basePath->__invoke('js/custom.js');
or, since declaring the invoke method allows you to call an object as if it were a function you can write the same thing like this
$basePath = $viewHelperManager->get('BasePath');
$basePath('js/custom.js');
$viewHelperManager = $e->getApplication()->getServiceManager()->get('viewhelpermanager');
$headScript = $viewHelperManager->get('HeadScript');
$headScript->prependFile($viewHelperManager->getRenderer()->basePath('js/bootstrap.min.js'));
$headScript->prependFile($viewHelperManager->getRenderer()->basePath('js/jquery.min.js'));
$headScript->prependFile($viewHelperManager->getRenderer()->basePath('js/respond.min.js'),'text/javascript', array('conditional' => 'lt IE 9'));
$headScript->prependFile($viewHelperManager->getRenderer()->basePath('js/html5shiv.min.js'),'text/javascript', array('conditional' => 'lt IE 9'));
Related
I'm trying to set multiple values for a select object with Zend Framework 2's form class but it's only passing one value. Here is my code:
public function addphotosAction()
{
$identity = $this->identity();
$files = array();
$album_name = array();
foreach (glob(getcwd() . '/public/images/profile/' . $identity . '/albums/*', GLOB_ONLYDIR) as $dir) {
$album_name = basename($dir);
$files[$album_name] = glob($dir . '/*.{jpg,png,gif,JPG,PNG,GIF}', GLOB_BRACE);
}
$form = new AddPhotosForm();
$form->get('copy-from-album')->setValueOptions(array($album_name));
return new ViewModel(array('form' => $form, 'files' => $files));
}
I know it has to do with $album_name but am at a loss about how to use it to grab all the directories (if I try to write to $album_name via []), I get an warning of
`Warning: Illegal offset type in C:\xampp\htdocs\module\Members\src\Members\Controller\ProfileController.php on line 197`
which is the $files[$album_name] = glob($dir . '/*.{jpg,png,gif,JPG,PNG,GIF}', GLOB_BRACE); line.
As I said, I am at a loss about how to edit this to grab all the directories.
Any help would be appreciated.
Thanks!
here is a screenshot of what I am trying to describe: http://imgur.com/OGifNG9
(there is more than one directory that exists but only one is being listed in the select menu).
I really recommend to do it with a factory. With a factory you 'll write this code once and can use it everywhere else in your code. For object orientated reasons, in which everything should be an object, I recommend using PHP 's own DirectoryIterator class instead of glob. The code in the controller should be kept as small as possible. Please have a look at the following example code.
The Form Factory with the Directory Iterator
The form factory intializes the form class with everything you need for the form instance for you, so this code won 't show up in the controller. You can re-use it for an inherited edit form for example.
<?php
namespace Application\Form\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Form\AddPhotosForm;
class AddPhotosFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $oServiceLocator)
{
$oParentLocator = $oServiceLocator->getServiceLocator();
// please adjust the dir path - this is only an example
$aDirectories = [];
$oIterator = new \DirectoryIterator(__DIR__);
// iterate and get all dirs existing in the path
foreach ($oIterator as $oFileinfo) {
if ($oFileinfo->isDir() && !$oFileinfo->isDot()) {
$aDirectories[$oFileinfo->key()] = $oFileinfo->getFilename();
}
}
// set option attribute for select element with key => value array of found dirs
$oForm = new AddPhotosForm();
$oForm->get('mySelectElement')
->setAttributes('options', $aDirectories);
return $oForm;
}
}
That 's all for the factory itself. The only thing you have to do is writing it down in your module.config.php file.
...
'form_elements' => [
'factories' => [
AddPhotosForm::class => AddPhotosFormFactory::class,
],
],
...
Using ::class not just cleans things up, it will lead to using fewer strings and this makes things easy to remember in an IDE with autocompletion for class names.
The Controller
With the factory we cleaned up the controller. In a controller code should be as small as possible. Using factories is the solution for many problems, which may happen in a later process of coding. So keep it always clean and simple.
...
public function indexAction()
{
$oForm = $this->getServiceManager()
->get('FormElementManager')
->get(AddPhotosForm::class);
return [
'form' => $oForm,
}
}
That 's all for the controller so far. Your select element was populated in the factory and your controller is easy to understand and as small as it should be.
I know this is odd, but I'm trying to provide a pass through interface in a taglib that allows the caller to pass in any other tag to be displayed in a container with additional processing.
To this effect, I'm trying to dynamically call an arbitrary tag in an arbitrary namespace. This may be clearer by example.
GSP:
<myLib:myTag someProp="blah" anotherProp="blah2" size="80" namespace="g" tag="textField">
In my taglib, I'm trying to display the tag they pass.
Taglib:
def myTag = {
String id = //some processing, not specified by caller
attrs.put("id", id)
def namespace = attrs.remove("namespace")
def tag = attrs.remove("tag")
out << ?????
}
The problem comes after the out... I'm having trouble calling the tag. I've tried the following with the following errors
namespace.tag(attrs) //No signature of method: java.lang.String.tag()
namespace."${tag}"(attrs) //No signature of method: java.lang.String.textField()
"${namespace}"."${tag}"(attrs) //No signature of method: java.lang.String.textField()
This seems to work, but the method needs to support tags in other namespaces
g."${tag}"(attrs)
So the question is How can I use reflection to use a dynamically defined taglib?
I don't have them pass the fully formed tag in the body() because I need to interact with it in the taglib.
I believe the following works, I'm not completely certain this is the best answer, so will leave the question open for suggestions from others.
String namespace = attrs.remove("namespace")
String tag = attrs.remove("tag")
GrailsTagLibClass tagLibClass = grailsApplication.getTagLibClasses().find { it.namespace == namespace && it.hasTag(tag)}
def tagLibBean = grailsApplication.mainContext.getBean(tagLibClass.getFullName())
out << tagLibBean."${tag}"(attrs)
I have seen a very interesting thing. I did a little mvc/rest framework based on the Slim framework.
$app->put('/:id', function ($id) {
$app->halt(500, "Error") // Here this is working.
(new RestController)->editItem($id);
})->via('put');
So I wrote a RestController which extends the BaseController, and my BaseController extends the Slim framework.
class BaseController extends \Slim\Slim {
/**
* #var \app\models\AbstractModel
*/
protected $model;
public function __construct() {
$settings = require(__DIR__ .'/../configurations/slim.php');
parent::__construct($settings);
}
}
So my BaseController can uses the Slim class's methods and properties.
class RestController extends BaseController {
public function editItem($id) {
$data = $this->getRequestBody();
$result = $this->model->update($id, $data['data']);
// This is absolutely not working, but it seems my application will die in this case.
// Because I cannot see any written message (with echo or print methods...)
// This will always return with a 200 staus code and blank page!
$this->halt(404, json_encode(array('status' => "ERROR")));
}
}
But this will work fine... and I do not get it, why?
class RestController extends BaseController {
public function editItem($id) {
$data = $this->getRequestBody();
$result = $this->model->update($id, $data['data']);
// This will work.
$app = Slim::getInstance();
$app->halt(204, json_encode(array('status' => "ERROR")));
}
}
Anyone has a good ide?
You construct a new RestController in your route by doing (new RestController). Although it extends Slim/Slim in the class hierarchy, it is a new instance of it; it is not a copy of or reference to $app, the Slim application that is actually being run.
This causes issues in the first case: you say $this->halt(...) while $this is the newly constructed RestController which is a new instance of a Slim app, not the one that is currently running. Therefore the halt call has no effect on your the output of your application.
In the second case, you say $app->halt(...) where $app is Slim::getInstance(), the global instance of your Slim application, which is the actual running Slim app. Therefore the halt call has effect on the output of your application.
You can solve the issue either by using the second approach, or by instantiating your global $app variable as a RestController, and then you can do:
$app->put('/:id', function ($id) use ($app) {
$app->halt(500, "Error") // Here this is working.
$app->editItem($id);
})->via('put');
NB; you forgot to put use ($app) in the code posted to your question, I added it in my code above. Is it present in the code you are actually running? Otherwise the $app->halt() call should result in an error in any case.
How can I inject the "normal" ServiceManger into a custom validator used for REST calls (Use without Form). ZF 2.2.7 Used to inject an instance of external library into an validator.
I have tried the following, and nothing works:
Inject it with the ValidationPluginManager, service not found
Inject it via factory, factory will not be loaded in validator chain
Inject it via validator options, not possible because the "ServiceManager" is an instance of ValidationPluginManager with the asme result as mentioned in #1
Is there any concept how to solve this problem, or do i have to give up and link all libraries statically?
Not tested this and have never done with with ValidationPluginManager but works with ControllerManager, FormElementManager etc
// GetServiceLocator call should return Instance of ServiceManager
// Then retrieve the service, Yay!
$validationPluginManager->getServiceLocator()->get('SomeService')
There has been a discussion on github about a somewhat similar problem here. They suggested to use Zend\Form\FormAbstractServiceFactory and tinker with dependencies there (weierophinney before closing the topic).
In your post you mention you are not using a form did you mean you are not using the form in a classic kind of way or are you bypassing the whole form in particular?
It simply seems off to me to use a validator if there isn't a form present. Could you elaborate more on that?
EDIT: To my understanding zf2 requires that your input filters have form elements like 'inputs' etc. You did not post any code and I simply do not know if/or your able to bypass this somehow. I still do not understand why you'd still want to use validators in combination of input filters. I would simply skip the input filters and write the custom validator.
My personal preferences is to write factories instead of anonymous functions within module.php files. But this also could work the anonymous function way.
I would then simply resolve the dependencies within the customValidatorFactory and get the factory within my controller or whatever place I would need it.
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use CustomValidator;
class CustomValidatorFactory implements FactoryInterface
{
/**
* Create Service Factory
*
* #param ServiceLocatorInterface $serviceLocator
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$sm = $serviceLocator->getServiceLocator();
$customService = $sm->get('Application\Service\Geocoding');
$validator= new CustomValidator();
$validator->setCustomService($service);
return $validator;
}
}
// CustomValidator.php
class CustomValidator extends Zend\Validator\AbstractValidator
{
public function setCustomService($service)
{
$this->service = $service;
}
public function isValid($value)
{
$customService = $this->service;
if ($customService->customMethod() == true) {
return true;
}
return false;
}
}
//module-config.php
'service_manager' => array(
'factories' => array(
'custom\ValidatorFactory' => 'Namespace\To\CustomValidatorFactory',
),
),
//yourController or whatever.php will require access to the service manager
$customValidation = $sm->get('custom\ValidatorFactory');
// should return true or false now
$state = $customValidation->isValid($someValue);
I have a component that has been happily building and rendering menus for a while now. Now I have to provide for a special case that shares all of the same logic, but requires a little bit of work in front of what already exists. What I'd like to do is create a new component action that will do the necessary preprocessing, punt to shared logic to complete the computational side and then render through the existing template partial (when all is said and done, it's still a menu like any other--it just take a little more work to build it).
Unfortunately, I can't find any way of doing this.
Here's the high level file/code breakdown that I have right now:
#
# navigation/actions/components.class.php
#
public function executeMenu() {
/**
* This method runs most of the menus and does most of the work
* that's required of the special case.
*
* Once complete, of course, it renders through navigation/templates/_menu.php
*/
}
public function executeSpecialMenu() {
/**
* Do some preparatory work and delegate to executeMenu()
* to finish up and render the menu. I'd like this action
* to render through the _menu.php partial as well.
*/
}
#
# templates/layout.php
#
<?php include_component( 'navigation', 'menu', array( 'menu' => 'Entity Type' ) ) ?>
/** SNIP */
<?php include_component( 'navigation', 'SpecialMenu' ) ?>
Any input would be much appreciated.
A simple if non-optimal way would be to create the _SpecialMenu.php partial and just place an include inside it:
<?php include_partial('navigation/menu', array('menu' => 'Entity Type', 'other_var' => $other_var) ?>
Where each of your variables will need to be passed to the partial as in $other_var. Does this at least solve the problem?
A more elegant solution is to use the get_partial inside the "second" component's execute function, like so:
public function executeSpecialMenu() {
//forces SpecialMenu to render _menu.php
echo get_partial('menu', $this->varHolder->getAll());
return sfView::NONE;
}
The call to varHolder->getAll gets all the variables that were going to be passed to the "normal" partial, since get_partial requires that.
Or, as a new method:
public function executeSpecialMenu() {
return $this->renderAlternatePartial('menu');
}
protected function renderAlternatePartial($partial) {
echo get_partial($partial, $this->varHolder->getAll());
return sfView::NONE;
}
Also there exists a renderPartial('xxx') method in the action class which is useful when it is needed to generate a part without template in cases such as XmlHttpRequest s:
if ($request->isXmlHttpRequest())
{
return $this->renderPartial('module/action', array('param' => 'value'));
}
I haven't tested if this works in the component execute methods. If this does not work it is a good idea to add such a functionality to symfony sfComponent class.
In the action/template mode, there exists a $this->setTemplate('xxx') method (in the action class) which can use a same template for different actions. (e.g same template for new or edit actions). Would that there was such a method in the component classes.
I wouldn't recommend to use different actions to render the same entity. Try to combine them and call a component with different parameters, and if it is heavy, move all the logic to a separate class.