I am trying to create an extension to behat progress output step formatter.
The goal is simply change the . to a * for each passed scenario step.
The behat documentation does not even mention the ability to create a custom formatter, however I found a GitHub repository that does this behat-format-progress-fail
But no clear / simple overview of how to achieve this is there, I have tried duplicating and modifying them. Is there a simple example or clear documentation for this?
By creating a very cut down version of ProgressStepPrinter.php and then including that in autoload-dev in composer.json uses it in prefernce to the one from Behat.
ProgressStepPrinter.php
namespace Behat\Behat\Output\Node\Printer\Progress;
use Behat\Behat\Output\Node\Printer\Helper\ResultToStringConverter;
use Behat\Behat\Output\Node\Printer\StepPrinter;
use Behat\Behat\Tester\Result\StepResult;
use Behat\Gherkin\Node\ScenarioLikeInterface as Scenario;
use Behat\Gherkin\Node\StepNode;
use Behat\Testwork\Output\Formatter;
final class ProgressStepPrinter implements StepPrinter {
private $resultConverter;
public function __construct(ResultToStringConverter $resultConverter) {
$this->resultConverter = $resultConverter;
}
public function printStep(Formatter $formatter, Scenario $scenario, StepNode $step, StepResult $result) {
//custom logic to print per step here
}
}
composer.json
"autoload-dev": {
"files": [
"features/bootstrap/ProgressStepPrinter.php",
]
},
Related
First off, the issue/question arose with Laravel 5.6 and PHP 7.4.10. I know that 'magic strings' for controller calls have been deprecated as of recent Laravel versions, but I'm interested in the underlying infrastructure in this question.
PREREQUISITES
Suppose I have two folders: project and core.
project contains a freshly installed laravel project;
core contains some package-like structure of namespaces and classes (not actually a package in the laravel sense), which is being autoloaded by the project.
For a minimal working example, you can see the last commit of the repository I published about this. I'm going to post the main files' contents here as well, but you can actually reproduce and play around with the sample projects yourself.
Basically the concept is pretty standard, much like a package: I want to have some reusable logic inside of my core with some default implementations. In the project I may or may not overwrite some of the functions, but for the sake of the question's simplicity, my core only defines a Fruit module (just a folder with a namespace) containig three files:
fruit_routes.php
<?php
Route::get('/pear', 'FruitController#pear');
Route::get('/apple', 'FruitController#apple');
FruitController (This is where the question is focused)
<?php
namespace CORE\Fruit;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class FruitController extends Controller
{
public function pear()
{
//if we call the action '\CORE\Fruit\FruitController#apple' instead, it works :)
return redirect()->action('FruitController#apple', ['message' => "No pears available! :( "]);
}
public function apple(Request $request)
{
return $request->message . "There you have an apple!";
}
}
FruitServiceProvider
<?php
namespace CORE\Fruit;
use Illuminate\Support\ServiceProvider;
class FruitServiceProvider extends ServiceProvider
{
public function register()
{
/*
* Map routes from our Fruit module to the controller's namespace
*/
$this->app->router->namespace('CORE\Fruit')->group(__DIR__."/fruit_routes.php");
}
}
And then in the project I simply include the following two lines:
composer.json
{
//..
"autoload":
//...
"psr-4": {
"App\\": "app/",
"CORE\\" : "../core"
}
},
}
config/app.php in $providers array
/*
* Package Service Providers...
*/
CORE\Fruit\FruitServiceProvider::class,
Again, for the full sample structure and contents, refer to the MWE repo.
THE QUESTION
Although the namespace for the controller classes has been explicitly declared from the FruitServiceProvider's register() method for the fruit_routes.php file, Laravel still fails to recognize that same namespace when using rediret()->action() from within those same controllers.
In the given FruitController you can see:
return redirect()->action('FruitController#apple');
and this will fail with Action App\Http\Controllers\FruitController#apple not defined.
As you can see, Laravel still searches for the controller inside the current project's default controller namespace (in this case: App\Http\Controllers)
Fortunately, passing the fully qualified name of the controller solves the issue:
return redirect()->action([self::class, 'apple']);
//Or alternativelly, but really clumsy:
//return redirect()->action('\Core\Fruit\FruitController#apple'); //notice the slash at the beginning
I have the suspicion that I must somehow also inform the redirect() helper (and actually, the underlying Redirect facade) that I want it to reference the controllers inside of my CORE\Fruit namespace whenever called from within that namespace... Or what would be the right approach? Is that desired behavior and am I missing something? And again, as mentioned in the beginning, I know that 'magic strings' are not the best practice and the most beloved feature of Laravel, but I really want to understand how things work in this scenario.
I also found this issue on github with a realted topic, but no answer there as well. As for people who are about to comment 'just avoid using magic strings', I'm stuck with a project I inherited and rewriting all of the core's magic string controller references is really not an option I would love to embrace.
Any insight is appreaciated! Many many thanks in advance!
I'm new to CI and am struggling to get my head around it.
I'm familiar with Laravel and Symfony and I'm finding it very difficult to test CI code.
I'm considering the service locator pattern to try and work around the dependency injection limitations, but right now I'm struggling with autoloading.
Let's say that I have a model like this:
<?php
class FooModel extends CI_Model
{
public function __construct()
{
parent::__construct();
$this->load->library('alertnotificationservice');
}
}
I want to write a test that looks like this:
<?php
namespace Test\AlertNotification;
// extends TestCase and offers reflection helper methods
use Test\TestBase;
class FooModelTest extends TestBase
{
public function test_my_method()
{
$objectUnderTest = new \FooModel();
}
}
When I run my test I get the error Error: Class 'CI_Model' not found.
I'm using CodeIgnitor 3.1.2 and it doesn't use composer or include the phpunit.xml.dist file that the version 4 manual refers to.
What is the "proper" way to get the autoloading to happen so that I can run my tests?
I haven't found a satisfactory way to do this. I ended up creating a bootstrap.php file that I include from phpunit.xml.dist
It looks something like this:
<?php
require(__DIR__ . '/../vendor/autoload.php');
// this is a copy of the default index.php shipped with CodeIgnitor
// The system and application_folder variables are replaced
// Also, in this version we do not bootstrap the framework and rather include our own version below
require('loader.php');
// this is a modified version of system/core/CodeIgniter.php
// they do bootstrapping, routing, and dispatching in one place
// so we can't use the whole file because dispatching fails when running tests
require('framework.php');
// set up the test environment database connection
putenv('DATABASE_HOST=localhost');
putenv('DATABASE_USER=user');
putenv('DATABASE_PASSWORD=password');
putenv('DATABASE=control_panel');
// CI uses a singleton approach and creates an instance of a child of this class during dispatch
// We need to make sure that the singleton holder is populated
$controller = new CI_Controller();
The framework.php is a stripped down version of that CodeIgnitor file where I've removed the routing and dispatch logic. I've put the files up as a Gist
The crux of the loading in CI seems to exist in system/core/Controller.php and the controller is intended to be something that lets "so that CI can run as one big super object". The load_class function (declared in system/core/Common.php) is responsible for hunting down and loading the class files.
I should also include my composer.json file. I'm using this for testing (CI 3.1.12 does not use composer)
{
"require": {
"guzzlehttp/guzzle": "^6.5"
},
"require-dev": {
"phpunit/phpunit": "^9.1"
},
"autoload": {
"psr-4": {
"Test\\": "tests/"
},
"classmap": ["application/", "system/"]
}
}
I would really like to avoid loading absolutely everything, and would like to be able to mock out bits and pieces, but I'm not optimistic that CodeIgnitor lends itself to this.
Anyway, this approach at least lets me boot my app. There has to be a better way of doing this, I can't believe that the framework could be so popular if it's so hard to test properly.
So subject is the question. Yes, I've searched this forum and googled too. All I've got - useless Symfony docs and casts, some general advises, cli-s and nothing case specific. Maybe yahoo or duckduck could help better?
Everyone is talking about bundles, about how it is important to create them, probably because under the hood Symfony is pushing users away from custom libraries, but no one is actually explains how to start using a bundle - how to start calling its methods.
No, my library is not a composer or whatever package. No, library methods do not return Response objects. No, I am not dealing with composer or recompilations or cli (I use Composercat). No, I will not put library to github or packagist to load it via composer or whatever because it is private library.
Sorry about emotional off-topic.
About the case: I've put my library into the folder
src/lib/MyLibrary.php
I suspect that library class is autoloaded, because if I do not extend Controller with it (if I declare class MyLibrary instead of class MyLibrary extends Controller) - Symfony spits "class name in use" error.
So question: in my controller how to call library method?
$this->get('MyLibrary') doesn't work.
echo print_r($this) doesn't show MyLibrary in this registry too.
Looks like library file is loaded but not registered and/or instantiated. If it is so, then where to point Symfony to register it?
So most of this question is really about how php manages classes. Not so much about Symfony. But that's okay.
To start with it would be best to move project/src/lib to just project/lib. Symfony has some scanning stuff going on in the src directory and you really don't want to have your library mixed up in it.
So:
# lib/MyLibrary.php
namespace Roman;
class MyLibrary
{
public function hello()
{
return 'hello';
}
}
Notice that I added a namespace (Roman) just to distinguish your code from Symfony's.
Now you need to tweak composer.json in order to allow php to autoload your classes:
"autoload": {
"psr-4": {
"App\\": "src/",
"Roman\\": "lib/"
}
},
After adding the Roman line, run "composer dump-autoload" to regenerate the autoload files.
After that, it's just a question of using regular php inside of your application:
# src/Controller/DefaultController.php
namespace App\Controller;
use Roman\MyLibrary;
use Symfony\Component\HttpFoundation\Response;
class DefaultController
{
public function index()
{
$myLibrary = new MyLibrary();
$hello = $myLibrary->hello();
return new Response($hello);
}
}
And that should get your started.
i have some custom function and i'm trying to use that into project, for example:
function makeText($str1, $str2){
return $str1 . ' '. $str2;
}
and i want to use this function in view such as :
<div style='float:left;'>MakeText : {{makeText("Hello","World");}}</div>
makeText is only sample function, witch folder must be put functions method such as UF.php containes all functions and how to define this file to laravel and use it?
You could follow Laravel’s conventions and create a helpers.php file in your app directory. Be sure to auto-load it with Composer though:
"autoload": {
"classmap": [
//
],
"files": [
"app/helpers.php"
]
},
You can then use the function any where in your application, including views.
Laravel gives you a few options. You can include your function definition inside of any of the files that get automatically included and achieve the result you want, such as /app/start/global.php, /bootstrap/start.php, /app/routes.php or many others. The problem with this approach is that, depending on the name of your function, there is a non-negligible likelihood that the name might conflict with one that is already taken (or may get taken later). Also, if you ever need to debug this function you will need to be able to find it later.
You can get around this issue by placing your function inside of a class, and then call that class a service. You can then inject that class into your controller via dependency injection and then pass that data to your view:
class MyService
{
public function makeText($param1, $param2)
{
return $param1 . ' ' . $param2;
}
}
class AController extends BaseController
{
public function __construct(MyService $serv)
{
$this->serv = $serv;
}
public function aRoute()
{
return View::make('some.view')
->with('serv', $this->serv);
}
}
And then in your view:
<div style='float:left;'>MakeText : {{ $serv->makeText("Hello","World"); }}</div>
This will help you prevent naming collisions because you can easily place MyService into any namespace that makes sense. It will also help you keep your code organized better.
Something this simple will probably not require a service provider, but as you add complexity to your project it would be an easy step to do once you need to.
I want to add Accessors and Mutators to a model. In Laravel 4 it worked all fine, but with Laravel 5 I have some trouble.
I have a "lib" folder in my App directory which contains the "db_transformers.php" file. This file holds classes like "dbDate" with a set and get function to transform dates stored in the database to a user-friendly format.
The "db_transformers.php" file is namespaced:
<?php namespace App\lib;
I also rerfer to the folder in my model:
use App\lib;
But my methodes still throw errors:
public function getDateTimeAttribute($value)
{
return dbDate::get($value);
}
This will return a "Class 'App\dbDate' not found" error.
What could be my problem?
You're confusing autoloading (PHP including/requiring a class definition file) with namespaces (a system that allows hierarchical naming of PHP classes/functions to help prevent code conflicts).
It's an easy thing to do. Covering the changes to autoloading in Laravel 5 is beyond the scope of a Stack Overflow question, but if you're interested I've written a multiple article series on how autoloading works with composer/Laravel 4/Laravel 5.
To your specific question, you say you've defined a class named dbDate in a file named db_transformers.php, and db_transformers.php has a namespace of App\lib.
#File: lib/db_transformers.php
namespace App\lib;
//other code
class dbDate
{
//other code
}
//other code
This mean your class's full name is App\lib\dbDate. The entire thing is the class's name. That's probably the biggest thing to get used to with namespaces in PHP.
This means if you wanted to use the class in other code, you'd need to refer to the full class name, including a leading backslash.
return \App\lib\DbDate::get($value);
You could also import the class using the use keyword
use App\lib\DbDate;
//other code
public function getDateTimeAttribute($value)
{
//since we imported the class with `use`, we don't need to type the full name
return DbDate::get($value);
}
The use keywords imports a specific class into the current namespace. When you said
use App\lib;
you were telling PHP
You know that global classApp\lib? I'm going to refer to it below as lib
Since you don't have a class named lib, this is meaningless, and it's why your use didn't help.
So that's namespaces. The other problem you need to solve is autoloading. Autoloading is what lets you skip the require or include statement/function when you want a class definition files in your project.
Laravel 4 used a bunch of different autoloaders, including something called a classmap autoloader. The classmap autoloader automatically parses all the files in your project looking for classes, and creates a giant map of which class is where (that's over simplifying it a bit, see the article series I linked earlier for the full details).
In Laravel 4, the classmap autoloader probably read the file in lib for you. Laravel 5 reduced the number of autoloaders, which included getting rid of the classmap autoloader for most folders.
The simplest thing you can do in Laravel 5 is to configure your project to use the classmap autoloader again. Open up composer.json and find this section
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
}
},
And add lib to the classmap autoloader section
"autoload": {
"classmap": [
"database",
"lib"
],
"psr-4": {
"App\\": "app/"
}
},
This tells composer to include the lib folders when it creates its autoloader files. You'll need to run the dumpautoload command
composer dump-autoload
after doing that, and you should be able to use the classes defined in lib/db_transformers.php as you wish.
You need to use the complete class name: use App\lib\dbDate;
You might also look into using view decorators for this purpose, as doing it in your model is really not appropriate.
Several packages exist to help with this, e.g. https://github.com/ShawnMcCool/laravel-auto-presenter