I'm trying to add a custom assertion to the TestReponse class so I can make something like this:
$response = $this->json('POST', '/foo/bar');
$response->myCustomAssertion();
I tried creating an App\TestResponse class that extends the original one and then binding it in the App\Provider\AppServiceProvider class.
public function register()
{
$this->app->bind('Illuminate\Foundation\Testing\TestResponse', function ($app) {
return new App\TestResponse();
});
}
But $response->json() is still returning the original one and not my own implementation.
How can I extend the TestResponse class?
If you want a little more fine-grained control, you can also extend the Illuminate\Foundation\Testing\TestResponse, as you have done, and then override the createTestResponse method in your TestCase class to return an instance of your custom response class:
// Laravel 8 and above
protected function createTestResponse($response)
{
return tap(App\TestResponse::fromBaseResponse($response), function ($response) {
$response->withExceptions(
$this->app->bound(LoggedExceptionCollection::class)
? $this->app->make(LoggedExceptionCollection::class)
: new LoggedExceptionCollection
);
});
}
// Before Laravel 8
protected function createTestResponse($response)
{
return App\TestResponse::fromBaseResponse($response);
}
From Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.
The TestResponse class uses the Macroable trait so you can add macro functions at runtime.
TestResponse::macro('nameOfFunction', function (...) {
...
});
You can add this to a Service Provider's boot method or somewhere before you need to make the call to that macro'ed method.
Related
I am struggling with extending a Plugin in OctoberCMS.
I need to access a protected property, so I wanted to create a new getter, that would return the value, but it always returns NULL
Here an example code of the controller (I cannot extend it here, as this is a 3rd party plugin):
class Records extends Controller
{
protected $some_value;
}
And this is how I implement it in the bootmethod of my Plugin:
Records::extend(function($controller) {
$controller->addDynamicMethod('myValue', function() use ($controller) {
return $controller->some_value;
});
});
But this does not work. When I dump the $controller I get sth like this:
MyNamespace\MyPlugin\Controllers\Records {#1616 ▼
#some_value: "1"
...
But when I want to return the value, it is null.
There is one hack that I used once. I was also facing the same issue
ref: https://tutorialmeta.com/octobercms/how-access-private-property-october-cms
// class
class Records extends Controller
{
protected $some_value;
// or private $some_value;
}
// in pugin
use Symfony\Component\VarDumper\Cloner\VarCloner;
Records::extend(function($controller) {
$controller->addDynamicMethod('myValue', function() use ($controller) {
$cloner = new VarCloner;
$cloned = $cloner->cloneVar($controller);
return $cloned->some_value;
});
});
It should do the trick and you can access variables.
please comment if any doubt
Okay there are questions about the same topic before but they don't help to fully understand this topic
SO SuggestionFirst
SO Suggestion Second
All the code is just to illustrate the situation, So this is the structure
A helper function which does something
namespace App\Helpers;
class Pets{
public function limit($string,$limit,$start = 0){
return substr($string,$start,$limit);
}
}
Now in order to use this helper, since it's a class so i need to create an object like this
CODE SAMPLE FIRST
namespace App\Objects;
use App\Helpers\Pets;
class User{
public function getShortUserName(){
$name = auth()->user()->first_name.' '.auth()->user()->last_name;
$pet = new Pets;
return $pet->limit($name,10);
}
}
But somewhere I got to know that if you add Facades before your namespace, you can call the function statically even if they are non static function like this
CODE SAMPLE SECOND
namespace App\Objects;
use Facades\App\Helpers\Pets;
class User{
public function getShortUserName(){
$name = auth()->user()->first_name.' '.auth()->user()->last_name;
return Pets::limit($name,10);
}
}
Now what I want to know is I have 2 sample codes with namespace as follows
use App\Helpers\Pets;
use Facades\App\Helpers\Pets;
By adding the Facades I can call the function statically but how, that's not a valida namespace in my app
What laravel doing behind the scene, I am so confused
Thank you for your time ;)
What you are describing is Laravels Real-Time Facades.
You can find documentation of the functionality here:
https://laravel.com/docs/6.x/facades#real-time-facades
I will not enter too much in details but this is a simple explanation of what's behind the scenes when you use facades in laravel.
Let's suppose you define a custom class with some public methods:
namespace Test;
class Foo
{
public function test()
{
return 'test';
}
}
Then you have to define a facade for this class:
namespace Test1;
class BarFacade
{
// In laravel this is called in the Facade abstract class but it is actually implemented
// by all the facades you add across the application
public static function getFacadeAccessor()
{
// In laravel you can also return a string which means that the object
// will be retrieved from the container.
return new \Test\Foo();
}
// In laravel this method is defined in the Facade abstract class
public static function __callStatic($method, $args)
{
$object = self::getFacadeAccessor();
return call_user_func_array([$object, $method], $args);
}
}
Then, you have to define the alias in the $aliases array of the config.app file. These aliases are parsed by laravel and registered using the php built-in function class_alias (see Illuminate/Foundation/AliasLoader.php)
class_alias('Test\Foo', 'BarFacade', true);
// You can also create an alias for the facade itself
class_alias('Test1\BarFacade', 'FooBar', true);
Then you can simply call the facades:\
var_dump(BarFacade::test());
var_dump(\Test1\BarFacade::test());
var_dump(\FooBar::test());
The results would obviously be:
string(4) "test"
string(4) "test"
string(4) "test"
I created an Artisan command which worked and where I injected a Kafka client service as the first parameter and a concrete class BudgetsTransformer, as the second parameter.
class ConsumeBudgetsCommand extends Command {
public function __construct(FKafka $kafkaClient, BudgetsTransformer $transformer)
{
$this->kafkaClient = $kafkaClient;
$this->transformer = $transformer;
parent::__construct();
}
}
AppServiceProvider class looked like:
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('kafka.client', function ($app) {
return new \Weq\FKafka\FKafka();
});
$this->app->bind('budget.transformer', function ($app) {
return new BudgetsTransformer();
});
}
public function boot()
{
$this->app->bind('consume:budgets', function ($app) {
return new ConsumeBudgetsCommand($app['kafka.client'], $app['budget.transformer']);
});
$this->commands('consume:budgets');
}
}
So far all is working properly. Then I decided to create a TransformerInterface which BudgedTransformer implements (and other future Transformers will implement it):
class BudgetsTransformer implements TransformerInterface
{
// ...
}
and I changed the signature in the command to inject the interface instead of the concrete class:
class ConsumeBudgetsCommand extends Command {
public function __construct(FKafka $kafkaClient, TransformerInterface $transformer)
{
$this->kafkaClient = $kafkaClient;
$this->transformer = $transformer;
parent::__construct();
}
}
But I get the following issue when I try to run some artisan command
In Container.php line 933:
Target [App\Transformers\TransformerInterface] is not instantiable while building [App\Console\Commands\ConsumeBudgetsCommand].
I run previously the issue the following artisan command just in case. cache:clear, clear-compiled, optimize and so on but no luck.
What I'm doing wrong? Should I bind the BudgetTransformer in a different way I'm doing now for passing and Interface instead of a concrete class?
I added:
$this->app->bind(TransformerInterface::class, BudgetsTransformer::class);
in AppServiceProvider::register() and I removed
$this->app->bind('budget.transformer', function ($app) {
return new BudgetsTransformer();
});
there, then I update in AppServiceProvider::boot() the command binding:
$this->app->bind('consume:budgets', function ($app) {
return new ConsumeBudgetsCommand($app['kafka.client'], $app[TransformerInterface::class]);
});
But still not working, anyway this approach (even working) will not resolve the issue since when I want to add another different transformer implementation, let's say CostTransformer which implements TransformerInterface is gonna always inject BudgetTransformer. So reading the documentation in the link, I found that Contextual Binding could be the solution, so I substituted by:
$this->app
->when(ConsumeBudgetsCommand::class)
->needs(TransformerInterface::class)
->give(function ($app) {
return new BudgetsTransformer();
});
So in that way, I will be able to inject different implementations of transformers to different commands by injecting the interface. But still not working.
Can someone tell me how exactly declare the command binding
$this->app->bind('consume:budgets', function ($app) {
return new ConsumeBudgetsCommand($app['kafka.client'], ???);
});
to use that Contextual binding?
For binding interfaces must be use this structure https://laravel.com/docs/5.5/container#binding-interfaces-to-implementations
$this->app->bind(TransformerInterface::class, BudgetsTransformer::class);
And
$this->app->bind('consume:budgets', function ($app) {
return new ConsumeBudgetsCommand($app['kafka.client'], $app->make(TransformerInterface::class));
});
I have a selection control on a blade form that is to be refreshed via ajax through this function:
function getOpciones(tbName) {
$.get('/ajax/read-data/' + tbName, function(data){
return (data);
});
}
The function takes a string variable 'tbName' whith the name of the table the control is related to, and passes it on as a parameter to the route:
Route::get('/ajax/read-data/{modelo}', 'AjaxController#readData');
Then the controller should get the parameter {modelo}, and retrieve the records in that table:
use App\RegFiscal;
public function readData($modelo) {
$arreglo = $modelo::all();
return response($arreglo);
}
But even though I am referencing the model with 'use App\RegFiscal', all I get is this error in laravel log:
2018-03-23 18:52:08] local.ERROR: exception
'Symfony\Component\Debug\Exception\FatalErrorException' with message
'Class 'RegFiscal' not found' in
C:\wamp64\www\laravel\cte\app\Http\Controllers\AjaxController.php:32
I´m new to Laravel, so needless to say I am lost and any help would be greatly appreciated. Thanks!
Just because you use App\RegFiscal doesn't mean $modelo is associated with it.
What you can do, though, is use app("App\\$modelo") to load in your model based on the parameter you get from the router. You would no longer need to use App\RegFiscal either.
$arreglo = app("App\\$modelo");
return response($arreglo::all());
This is assuming your model is stored in the default app directory within your Laravel project. If not you can change "App\" to where ever it is stored. If for example your model is in app\models\modelname.php it would be "App\Models\\$modelo".
You can do this as the following:
public function readData($modelo) {
$modelName = '\App' . '\\' . $modelo;
$class = new $modelName();
arreglo = $class::all();
return response($arreglo);
}
To those like me who wanted to inject it on a constructor, here's how to do it:
~$ php artisan make:provider MyProvider
Then override the register function like so:
class MyProvider implements ServiceProvider {
/** #override */
public function register() {
$this->app->bind(ShapeInterface::class, function ($app) {
return new Square($app->make(MyModel::class));
});
}
}
The ShapeInterface is a simple interface and Square is a simple class that implements the shape interface with a constructor parameter of the eloquent model.
class Square implements ShapeInterface {
private MyModel $model;
function __construct(MyModel $model) {
$this->model = $model;
}
...
}
I recently watched this video and wanted to change my Laravel controllers so that they had their dependencies managed with Laravel's IoC container. The video talks about creating an interface for a Model and then implementing that interface for the specific data source used.
My question is: when implementing the interface with a class that extends Eloquent and binding that class to the controller so that it is accessible from $this->model, should I also create interfaces and implementations for the Eloquent models which may be returned when calling methods such as $this->model->find($id)? Should there be different classes for the Model and the ModelRepository?
Put it another way: how do I do new Model when my model is in $this->model.
Generally, yes, people doing that pattern (the repository pattern) have an interface which have some methods defined that your app will use:
interface SomethingInterface {
public function find($id);
public function all();
public function paged($offset, $limit);
}
Then you create an implementation of this. If you're using Eloquent, then you can make an Eloquent implementation
use Illuminate\Database\Model;
class EloquentSomething {
protected $something;
public function __construct(Model $something)
{
$this->something = $something;
}
public function find($id)
{
return $this->something->find($id);
}
public function all() { ... }
public function paged($offset, $limit) { ... }
}
Then you make a service provider to put it all together, and add it into app/config/app.php.
use Something; // Eloquent Model
use Namespace\Path\To\EloquentSomething;
use Illuminate\Support\ServiceProvider;
class RepoServiceProvider extends ServiceProvider {
public function register()
{
$app = $this->app;
$app->bind('Namespace/Path/To/SomethingInterface', function()
{
return new EloquentSomething( new Something );
});
}
}
Finally, your controller can use that interface as a type hint:
use Namespace/Path/To/SomethingInterface;
class SomethingController extends BaseController {
protected $something;
public function __construct(SomethingInterface $something)
{
$this->something = $something;
}
public function home() { return $this->something->paged(0, 10); }
}
That should be it. Apologies on any errors, this isn't tested, but is something I do a lot.
Downsides:
More code :D
Upsides:
Able to switch out implementations (instead of EloquentSomething, can use ArraySomething, MongoSomething, whatever), without changing your controller code or any code that uses an implementation of your interface.
Testable - you can mock your Eloquent class and test the repository, or mock your constructor dependency and test your controller
Re-usable - you can App::make() to get the concrete EloquentSomething anywhere in your app and re-use the Something repository anywhere in your code
Repository is a good place to add additional logic, like a layer of cacheing, or even validation rules. Stock mucking about in your controllers.
Finally:, since I likely typed all that out and STILL DIDN'T ANSWER YOUR QUESTION (wtf?!), you can get a new instance of the model using $this->model. Here's an example for creating a new Something:
// Interface:
public function create(array $data);
// EloquentSomething:
public function create(array $data)
{
$something = this->something->newInstance();
// Continue on with creation logic
}
Key is this method, newInstance().
I've used $newModel = $this->model and it's worked for me.