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.
Related
Good morning,
I've been trying to use the removeByName method and it doesn't work.
I'm basically trying to hide a field in my DataObject within the forms that's generated by ModelAdmin, which manages the object.
See sample code below:
///DataObject snippet...
class MyObject extends DataObject{
public static $db = array(
'Title' => 'Varchar',
'Desc' => 'Text',
'Template' => 'HTMLText',
);
//#Override
public function getCMSField(){
$fields = parent::getCMSField();
$fields->removeByName('Template'); /// DOESN'T WORK!!!
return $fields;
}
}//class
Note: I'm not getting any errors. I'm just still seeing the field on the forms (Add and Edit) as usual.
Any help appreciated, thanks.
Okay, I found the issue.
I was just going over the API again for the millionth time, and recognized that I've named the function wrong. See correction below:
///Correction, forgot to add the 's' at the end of both the function and the parent call.
public function getCMSFields(){
$fields = parent::getCMSFields();
}
I can understand an error not being generated in Apache logs for the function because it's legit. But as for the parent call, it should of generated an error since the method don't exists. (Theory: Perhaps, since the function was never actually being called, the parent call wasn't being executed and thus no errors [run-time error]).
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);
update: if i can achieve same result using a different approach, please enlighten me.
I'm using/learning laravel 3 while building my project. Before coding any page-content at all, I'm verifying if i can deploy everything as planned, since this project is an actual rewrite of a rather huge app which is seriously outdated in the techniques it uses.
I'm struggling at this last part, which is quite possibly the hardest challenge i'll face to setup my project.
URL:
site.com/shops/__identifier__/controller/action/params
The above is the uri i'm trying to code atm.
The _identifier_ part should become a model (eloquent based)
the shops is the base for nested controllers
ie:
controllers/
- shops/
- home.php
- contact.php
- products.php
- etc ....
Each existing uri shops/identifier is a real site on its own. (though it has a different domain offcourse)
I want all my nested shops controllers to know what shop they're working with. In fact, the identifier will be used to load the correct layouts, to render the correct images, contact details etc...
From what i've read, i'll need to use the IoC functionality to inject the dependency of my shop-model into the constructor of my controller.
this is what i have atm:
file:application/start.php
/**
* Register IoC container for my nested shop controllers
*/
IoC::register('controller: shop', function($controller, $identifier)
{
//also tried using same line without the \\
$class = '\\Shops_' . ucfirst($controller) . '_Controller';
return new $class($identifier);
});
file:application/routes.php
/**
* Register all shop routes
*/
Route::any('/shops/(:any)/(:any?)/(:any?)', function($identifier, $controller = "home", $method = "index", $params = array()){
if($controller === "index")
$controller = "home";
$controller = IoC::resolve('controller: shop', array($controller, $identifier));
return $controller;
});
shop base-controller located at application/libraries/controllers/shop.php
<?php
namespace Controllers;
use Base_Controller;
/**
* Shop controller
*/
class Shop extends Base_Controller
{
public function __construct($identifier){
/**
* #todo: load the shop model using the identifier
* possibly move this after the parent::__construct()
*/
parent::__construct();
}
}
file: applications/controllers/shops/home.php
<?php
/**
* #heads up: Shop_Controller is aliased in application/config/application.php
*/
class Shops_Home_Controller extends Shop_Controller
{
public function get_index(){
return ('test');
}
}
Problems:
when defining my routes for these nested shops controllers. Do i simply return the controller laravel should use to resolve the request, or do i trigger the action myself in the callback function in that route definition?
controllers aren't autoloading (when trying the implementation above), yet i'm using the correct conventions for those controllers (unless i'm missing something :-) ). I'm guessing this is because i'm using IoC, how do i cleanly implement this or what is my mistake?
how do i trigger the correct action? It should, as expected, trigger the corresponding HTTP-verb action, since my nested controllers are also RESTFUL-controllers.
extra question to keep things as clean as possible: 'index' defaults to home controller when not using IoC functionality. Is my solution (if-condition in routes.php) to mimic this functionality a clean one? or is there any better approach?
By all means:
If my approach is way off, please tell me, i'm a newbie at laravel, and it's the first framework i'm using, so i'm a newbie at frameworks in general.
I'd also like to apologize if my question isn't explained to well so feel free to ask extra info.
I tried my best at googling this problem, but couldn't find anything similar, which is a first, since all my other laravel problems were easily solved using google.
I'd kindly thank anyone taking the time to read this and even better send me in the right direction!
Ok, final solution, this is far from clean if you ask me, but it seems to work, at least as far as i've checked.
I'm also not to sure if there is an alternative, but due to lack of response and timepressure, i decided to go with this and keep fingers crossed :(.
//start.php
IoC::register('controller: shop', function($id, $controllerName){
//controller name is the name of the controller located in the shops map
$class = "Shops_" . ucfirst($controllerName) . "_Controller";
include(path('app') . 'controllers/shops/' . strtolower($controllerName) . '.php');
return new $class($id);
});
//routes.php
Route::any("shops/(:any)/(:any?)/(:any?)/(:all?)", function($id, $controller = "index", $action = "index", $params = ""){
if($controller === "index")
$controller = "home";
$params = explode('/', $params);
$controller = IoC::resolve("controller: shop", array($id, $controller));
$http_verb = Request::method();
/**
* Need to return this, and i now need to manually return every response in every action in every shop controller
*/
return call_user_func_array(array($controller, $http_verb . '_' . $action), $params);
});
so example given
class Shops_Home_Controller extends Shop_Controller
{
public function get_index(){
/**
* this works when doing things the usual way, but will not return any output
* when working with nested dependency injection
*/
$this->layout->nest('content', 'shops.index');
}
public function get_test(){
/**
* this needs to return layout object if it is to work with the nested dependency injection
*/
$this->layout->nest('content', 'shops.index');
}
}
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.
I'm new to MSpec and would like to know if the way I wrote my test for ASP.NET MVC is correct. The test passes but I don't really like the way it's written and it seems awkward. I'm certainly missing something.
public class AccountControllerTests3
{
protected static AccountController controller;
static IFormsAuthenticationService formsService;
static IMembershipService membershipService;
protected static ActionResult result;
protected static LogOnModel model;
Establish context = () =>
{
var controllerBuilder = new TestControllerBuilder();
formsService = MockRepository.GenerateStub<IFormsAuthenticationService>();
membershipService = MockRepository.GenerateStub<IMembershipService>();
model = MockRepository.GenerateStub<LogOnModel>();
controller =
controllerBuilder.CreateController<AccountController>(new object[]
{
formsService,
membershipService
});
};
Because user_logs = () =>
{
bool rememberMe = false;
membershipService.Stub(
x => x.ValidateUser("bdd", "mspec")).Return(true);
formsService.Stub(x => x.SignIn("bdd", rememberMe));
controller.ModelState.IsValid.ShouldBeTrue();
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_good_login_and_password : AccountControllerTests3
{
private It user_should_be_redirected_to_the_home_page = () =>
{
model.UserName = "bdd";
model.Password = "mspec";
result = controller.LogOn(model, string.Empty);
result.AssertActionRedirect().ToAction<HomeController>(
x => x.Index());
};
}
[Subject(typeof(AccountController), "LogInTests")]
public class When_logging_into_application_with_bad_login_and_password : AccountControllerTests3
{
It The_error_message_should_be_shown = () =>
{
model.UserName = "BAD";
model.Password = "BAD";
result = controller.LogOn(model, string.Empty);
controller.ModelState[""].Errors[0].ErrorMessage.ShouldEqual(
"The user name or password provided is incorrect.");
};
}
Thanks in advance,
Thomas
One of my goals when I write tests with MSpec is to get the "Assert" or the "It" down to one line. MSpec is not like NUnit in that it only executes the Context (made up of the Establish clauses from the current class and all base classes and the Because clause) once followed by all of the Specifications (It clauses).
This is designed explicitly to force you to not perform any behavior in the It clauses, but rather observe it.
What you're actually doing here is using MSpec like NUnit. Try and rewrite the tests in a single class (using no inheritance). Work backwards... in the It, place a single line that asserts what you want to assert. Perhaps the AssertRedirect. In the Because, try and put a single line that causes the observations to be observable. This would probably be your call to the controller's logon method. Finally, in the "Establish context" you'd want to put everything else.
After a while, you may want to pull some of the things in the Establish context only into a base class, but in doing so, be sure that your entire subclass stands alone in terms of understanding. A reader shouldn't need to read the base class in order to understand what the actual spec is doing. It's ok to hide ceremonial implementation details, but be sure to hide them behind descriptive method names.
There's another line I'm not sure about:
controller.ModelState.IsValid.ShouldBeTrue();
If this is a test, it should probably be in its own It clause. Though really, do you want to test this? What are you testing here? Shouldn't your controller take an action based on whether or not the model is valid? Shouldn't the result of that action be observable (validation error instead of login error). I just wonder if you really need to test this.
A few other things to check out, first for styling with R#, it seems your tests are falling victim to R#'s defaults. I posted about how to fight this here:
http://codebetter.com/blogs/aaron.jensen/archive/2008/10/19/getting-resharper-and-vs-to-play-nice-with-mspec.aspx
Also, James Broome has some nice MVC MSpec extensions that are worth checking out:
http://jamesbroo.me/introducing-machinespecificationsmvc/
Good luck and Enjoy! Feel free to ping me on twitter if you have any other unrelated questions.
Here's a remark: instead of using CreateController method use InitializeController, because it is compile-time safer and refactor friendlier.
Instead of:
controller = controllerBuilder.CreateController<AccountController>(
new object[] { formsService, membershipService });
Do:
controller = new AccountController(formsService, membershipService);
controllerBuilder.InitializeController(controller);
The first will still compile if you change the controller constructor arguments and it will blow at runtime, while the second will generate a compile-time error.