Can't replicate Codeception dependency injection example from docs - php

I'm following the example from http://codeception.com/docs/07-AdvancedUsage#Dependency-Injection
Currently I have this in my Cest:
/**
* #var Helper\MyHelper
*/
protected $myHelper;
protected function _inject(\Helper\MyHelper $myHelper)
{
$this->myHelper = $myHelper;
}
And generates the following error:
Failed to inject dependencies in instance of 'HomeCest'. Failed to create instance of 'Helper\MyHelper'. Failed to create instance of 'Codeception\Lib\ModuleContainer'. Parameter 'config' must have default value.
This is my Helper:
<?php
namespace Helper;
class MyHelper extends \Codeception\Module
{
public function login($email, $password = '')
{
$I = $this->getModule('PhpBrowser');
$I->fillField('email', $email);
$I->fillField('password', $password);
$I->click('Ok!');
}
}
My goal is, if I can get this working, would be to create a BaseCest where I can inject all helpers, pageobjects and stepobjects.
The helper is properly loaded in acceptance.suite.yml.

The bug was in previous version of Codeception:
https://github.com/Codeception/Codeception/issues/2230
Codeception versions from 2.1.2 should not have this bug.

Related

Cannot enable doctrine's entity manager

I wanted to use Doctrine in my project, but I am not able to use Entity Manager.
I have created entites, repositories, config files and dbconnect but it seems that it's not done correctly.
Can you please check this code? Maybe I'm missing something really small.
My dbconnect file(it is bootstrapped in init.php):
<?php
namespace Projekt\Config;
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
$paths = array("Entity");
$isDevMode = false;
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'projekt',
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);
$em = EntityManager::create($dbParams, $config);
My Repository example:
<?php
namespace Projekt\Repository;
use Doctrine\ORM\EntityRepository;
/**
* Message
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class Message extends EntityRepository
{
public function getMessage($id)
{
$message = $this->find($id);
return $message;
}
public function getAllMessages()
{
}
public function createMessage()
{
}
public function updateMessage()
{
}
public function deleteMessage()
{
}
}
Now when I'm trying to access a default or custom repository method I get this error:
Warning: Missing argument 1 for Doctrine\ORM\EntityRepository::__construct(),
called in F:\xampp\htdocs\mvc\app\Controllers\Messages.php
on line 15 and defined in F:\xampp\htdocs\mvc\vendor\doctrine\orm\lib\Doctrine\ORM\EntityRepository.php on line 64
line 64 in EntityRepository.php is a __construct function that declares entitymanager, but it seems to not be working properly:
public function __construct($em, Mapping\ClassMetadata $class)
{
$this->_entityName = $class->name;
$this->_em = $em;
$this->_class = $class;
}
Two things that i noticed:
Your path is relative. Im not sure but i always use complete path to the Entity folder. You can use __DIR__ to achieve that easily. Depending on your namespace it should look Like:
$paths = array(__DIR__ . "/../Repository");
Doctrine needs to know where to find your entities and repositories. Depending on your namespace i would think your Repository file exists in a folder named "Repository" and not "Entity".
Have you correctly defined an Entity Class? Your Repository class looks ok to me but it can only work if you have a valid Entity class.
You should not name your repository "Message". The Entity should be named "Message" and the repository should be named "MessageRepository".

How to test custom validation rules in Laravel 5?

I created a custom validation rule in Laravel, extending it in the register() method of a service provider, and I'd like to test it, but don't know how.
I took a look at Laravel framework's validation tests, but I couldn't understand the purpose of the getTranslator() and getRealTranslator() methods.
Could someone give me a hint on how to test Laravel's custom validation rules?
EDIT
That's what I did:
Created a ValidatorServiceProvider as follows:
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ValidatorServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
$this->app['validator']->extend('greater_than', function($attr, $val, $params)
{
return false;
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
}
}
Also added it to the providers array and issued composer dump-autoload -o.
Added the following to tests\CustomValidationRulesTest.php:
<?php
use Mockery as m;
use Illuminate\Validation\Validator;
class CustomValidationRulesTest extends TestCase {
public function tearDown()
{
m::close();
}
public function testValidateGreaterThan()
{
$trans = $this->getTranslator();
$rules = [
'field2' => 'greater_than:field1'
];
$data = [
'field1' => 1,
'field2' => 2
];
$v = new Validator($trans, $data, $rules);
$this->assertTrue($v->passes());
}
protected function getTranslator()
{
return m::mock('Symfony\Component\Translation\TranslatorInterface');
}
protected function getRealTranslator()
{
$trans = new Symfony\Component\Translation\Translator('en', new Symfony\Component\Translation\MessageSelector);
$trans->addLoader('array', new Symfony\Component\Translation\Loader\ArrayLoader);
return $trans;
}
}
Running PHPUnit gives me the following:
PHPUnit 4.6.6 by Sebastian Bergmann and contributors.
Configuration read from /home/ubuntu/workspace/phpunit.xml
E.
Time: 248 ms, Memory: 14.75Mb
There was 1 error:
1) CustomValidationRulesTest::testValidateGreaterThan
BadMethodCallException: Method [validateGreaterThan] does not exist.
/home/ubuntu/workspace/vendor/laravel/framework/src/Illuminate/Validation/Validator.php:2615
/home/ubuntu/workspace/vendor/laravel/framework/src/Illuminate/Validation/Validator.php:372
/home/ubuntu/workspace/vendor/laravel/framework/src/Illuminate/Validation/Validator.php:372
/home/ubuntu/workspace/vendor/laravel/framework/src/Illuminate/Validation/Validator.php:325
/home/ubuntu/workspace/tests/CustomValidationRulesTest.php:27
What I'm doing wrong?
Thanks!
You need to understand a bit more the Container or IoC and how the Validator is registered there.
Laravel registers an instance of Illuminate\Validation\Factory as validator. So if you check the \Illuminate\Support\Facades\Validator, you find that it resolves to the Factory. When you extend the validator, you are in fact adding an extension in the Factory. Now, calling Validator::make() calls the Factory which has the extensions and it creates the Validator with the extensions, while instantiating a new Illuminate\Validation\Validator won't be able to resolve the extentions from the Factory.
You should not instantiate a new Validator, but use app('validator')->make().
Take it:
protected function getRealTranslator()
{
$loader = new \Illuminate\Translation\ArrayLoader;
$translator = new \Illuminate\Translation\Translator($loader, 'ja');
return $translator;
}

phpunit w/ laravel: missing argument when using providers

I'm running PHPUnit w/ Laravel. Here's my test:
class UserTest extends TestCase {
public function testSluggifyReturnsSluggifiedString($originalString, $expectedResult)
{
$url = new User();
$result = $url->sluggify($originalString);
$this->assertEquals($expectedResult, $result);
}
public function providerTestSluggifyReturnsSluggifiedString()
{
return array(
array('This string will be sluggified', 'this-string-will-be-sluggified'),
array('THIS STRING WILL BE SLUGGIFIED', 'this-string-will-be-sluggified'),
array('This1 string2 will3 be 44 sluggified10', 'this1-string2-will3-be-44-sluggified10'),
array('This! #string#$ %$will ()be "sluggified', 'this-string-will-be-sluggified'),
array("Tänk efter nu – förr'n vi föser dig bort", 'tank-efter-nu-forrn-vi-foser-dig-bort'),
array('', '')
);
}
}
As I'm familiarizing myself w/ unit testing, I've simply added the sluggify() function to the bottom of the User class.
I get this error:
There was 1 error:
1) UserTest::testSluggifyReturnsSluggifiedString
ErrorException: Missing argument 1 for UserTest::testSluggifyReturnsSluggifiedString()
If I change the test to define the two arguments (public function testSluggifyReturnsSluggifiedString($originalString='test', $expectedResult='test')) The test runs fine. For some reason it's not reading the provider data.
I suspect this is something about the Laravel setup, but I can't find anything in the docs to point me in the right direction. What am I doing wrong?
From PHPUnit docs on Data Provider:
The data provider method to be used is specified using the #dataProvider annotation.
So you have to add the annotation on top of your test method, for example:
class UserTest extends TestCase {
/**
* #dataProvider providerTestSluggifyReturnsSluggifiedString
*/
public function testSluggifyReturnsSluggifiedString($originalString, $expectedResult)
{
// ...
}
public function providerTestSluggifyReturnsSluggifiedString()
{
// ...
}
}

Laravel can't instantiate interface via __construct (using App::bind)

I am trying to resolve class via __construct using Laravel's bind() method.
Here what I do:
routes.php (of course I will move it away from here)
// Bindings
App::bind(
'License\Services\ModuleSelector\SelectorInterface',
'License\Services\ModuleSelector\ModuleSelector'
);
SelectorInterface.php - interface that I will expect in __construct method.
<?php namespace License\Services\ModuleSelector;
interface SelectorInterface {
/**
* Simply return query that will select needle module fields
*
* #return mixed
*/
public function make();
}
ModuleSelector.php - this is class that I want to resolve via Laravel's DI (see example below).
<?php namespace License\Services\ModuleSelector;
use License\Services\ModuleSelector\Selector;
class ModuleSelector extends Selector
{
/**
* Get module by it's code
*
* #return mixed
*/
public function find()
{
return $this->make()
->where('code', $module_code)
->first();
}
}
Module.php
<?php namespace License\Services\ModuleType;
use License\Services\ModuleType\TypeInterface;
use License\Services\ModuleSelector\SelectorInterface;
class Module
{
...
function __construct(SelectorInterface $selector)
{
$this->selector = $selector;
}
...
}
And the place when error occurs:
In my repo I have use License\Services\ModuleType\Module as ModuleService;.
Than there is method called find():
/**
* Find module by its code with all data (types, selected type)
* #return mixed
*/
public function find($module_code)
{
$module = new ModuleService;
// Get module id in order to use build in relations in framework
$module = $this->module->find($module_code);
...
}
So, in other words, I have 2 classes and one interface. What I am trying to do is:
1) Create Class1.php / Class2.php / Class2Interface.php.
2) In Class1.php in the __construct I specify __construct(Class2Interface $class2).
3) Instantiate Class2.
What I am doing wrong? Examples found here.
In this line:
$module = new ModuleService;
You are directly invoking the Module class and not passing in an instance of SelectorInterface.
For the IoC to work you bind and make classes using it. Try that line again with :
$module = App::make('License\Services\ModuleSelector\SelectorInterface');
An alernative is to inject it directly into your repos constructor, as long as the repo is created by the IoC container, your concrete will be automatically injected.
Nowhere do you have a class marked to actually "implement SelectorInterface".

How can I extend class Confide in Laravel 4?

I want to extend/overwrite the method logAttempt in class Confide (Confide on GitHub) in order to execute some extra code whenever someone logs in successfully. This would be cleaner than copying the same code to all controllers where logAttempt is called.
I read through the Laravel documentation and several answers here on stackoverflow, but I just can't get it working.
I created a new folder app/extensions with a file named Confide.php:
<?php
namespace Extensions;
class Confide extends \Zizaco\Confide\Confide {
public function __construct(ConfideRepository $repo) {
die('no way!');
$this->repo = $repo;
$this->app = app();
}
public function logAttempt($credentials, $confirmed_only = false, $identity_columns = array()) {
die('yeah man!');
}
}
I added the directory to my app/start/global.php:
ClassLoader::addDirectories(array(
// ...
app_path().'/extensions',
));
I also added it to composer.json and ran composer dump-autoload:
"autoload": {
"classmap": [
...,
"app/extensions"
]
},
My own Confide class seems not to be loaded at all, because Confide works as normal – without ever die()-ing.
And if I use \Extensions\Confide::logAttempt($input, true); in my controller including the namespace, I get this ErrorException:
Non-static method Extensions\Confide::logAttempt() should not be called statically, assuming $this from incompatible context
Do I really need my own ConfideServiceProvider class as well? I tried that, too, but I'm not sure at all what to put in there to make Confide use my extended class.
Is there no simple way to extend a tiny bit of a class? There must be, I'm just missing something here.
If you are looking to execute some code when a user logs in, you should just listen for that event. In this case, I believe Confide uses the Auth class to login, so you should be able to listen for that event.
Event::listen('auth.login', function($user)
{
$user->last_login = new DateTime;
$user->save();
});
I find this much easier and cleaner than worrying about extending classes.
EDIT: Made a mistake
I think you need to call the method like this:
\Extensions\Confide->logAttempt($input, true);
because you are using:
\Extensions\Confide::logAttempt($input, true);
Which is how you call static methods.
I think I finally figured it out.
I had to extend ConfideServiceProvider as well like so:
<?php
namespace Extensions;
class ConfideServiceProvider extends \Zizaco\Confide\ConfideServiceProvider {
/**
* Bootstrap the service provider.
*
* #return void
*/
public function boot() {
$this->package('extensions/confide');
}
/**
* Register the application bindings.
*
* #return void
*/
protected function registerConfide() {
$this->app->bind('confide', function($app) {
return new Confide($app->make('confide.repository'));
});
}
}
The code above goes into app/extensions/ConfideServiceProvider.php. Note: In boot() I replaced "zizaco" with "extensions" and in registerConfide() I made no changes at all, but if this method is not present in the extended class, the original class will be used. I've got no idea why.
Then in app/config/app.php I replaced Zizaco\Confide\ConfideServiceProvider with Extensions\ConfideServiceProvider.
My own extended Confide class looks like this now:
<?php
namespace Extensions;
class Confide extends \Zizaco\Confide\Confide {
public function logAttempt($credentials, $confirmed_only = false, $identity_columns = array()) {
$result = parent::logAttempt($credentials, $confirmed_only, $identity_columns);
if ($result) {
// Login successful. Do some additional stuff.
\Log::info('User ' . \Auth::user()->username . ' logged in.');
}
return $result;
}
}
Note: If you want to use any other standard Laravel class like Log, Session etc., prefix it with one backslash as shown in the example above, or add a use operator for each class you use (e.g. use \Log;).

Categories