I'm testing one of my controllers and no matter what I try I get the error that the all() function doesn't exist.
Static method Mockery_1_App_Models_User::all() does not exist on this mock object
My test method:
/**
* Test index page
* #return void
*/
public function testIndexAsUser()
{
$this->beUser();
// The method calls the mock objects should receive
$this->user->shouldReceive('all')->once()->andReturn([]);
// Call index page
$response = $this->call('GET', 'users');
// Assertions
$this->assertResponseOk();
$this->assertViewHas('user');
$this->assertViewNameIs('users.show');
}
My mocking method:
/**
* Mock a class
* #param string $class
* #return Mockery
*/
public function mock($class)
{
$mock = Mockery::mock('Eloquent', $class);
app()->instance($class, $mock);
return $mock;
}
My actual controller method:
/**
* Show all users
* #return Response
*/
public function getIndex()
{
$users = $this->user->all();
return view('users.index');
}
Am I using the wrong Eloquent class in my mock object or something? Since Laravel 5 the models are not referring to Eloquent but to Illuminate\Database\Eloquent\Model but I've tried that too.
The easiest way to mock an Eloquent model is by using partials:
$mock = m::mock('MyModelClass')->makePartial();
However, it won't help you much as you're using a static method (all()). PHP's not-so-strict nature lets you call static methods in a non-static way ($user->all()), but you should avoid it. Instead you should do it the heavy-handed way:
$users = $this->user->newQuery()->get();
This can be mocked:
$mockUser->shouldReceive('newQuery->get')->andReturn([/*...*/]);
If you want to take this one step further, move the get() call into a separate repository class that is injected into the controller, which will make it easier to mock. You can find plenty of articles on the repository pattern online.
Related
I have an old Laravel project that uses conception for tests
And there are two APIs that when I call the first one, it returns a specific resource as shown below:
class FirstResource extends JsonResource
{
public function toArray($request)
{
self::withoutWrapping();
return [
....
];
}
}
And the second API returns a resource as shown below:
class SecondResource extends JsonResource
{
public function toArray($request)
{
return [
....
];
}
}
JsonResource code (Laravel source code):
class JsonResource implements ArrayAccess, JsonSerializable, Responsable, UrlRoutable
{
/**
* The "data" wrapper that should be applied.
*
* #var string|null
*/
public static $wrap = 'data';
//...
}
The problem is that when these calls are made, the $wrap property in the second resource becomes null, even though its value should be equal to 'data', causing the test to fail.
Actually, the first resource affects the second resource on separate APIs!!!
Why it happens ?
I think Laravel-module makes just one instance of the app for all tests, so this conflict happens, am I right?
It can be fixed?
I have a variable, called $applicants and it contains data from users table and other tables from eager load.
Something like this:
Then I pass that variable to a Laravel Notification class via __construct method. The problem is if I dd the $applicant in the __construct method, the data is preserved, but if I dd it in the toMail method, it only contains data from user table.
Here is the code:
class DailyReportWasGenerated extends Notification implements ShouldQueue {
use Queueable;
private $applicants;
/**
* Create a new notification instance.
*
* #param $applicants
*/
public function __construct($applicants)
{
$this->applicants = $applicants;
dd($this->applicants->toArray());
}
public function toMail($notifiable)
{
dd($this->applicants->toArray());
}
I found the reason here: Relationship not being passed to notification?
So my solution is just convert my model collection to an array.
I have trouble with dependencies in my application in service layer.
I have following class:
<?php
class UserService{
private $userRepository;
private $vocationService;
private $roleService;
public function __construct(UserRepository $userRepository, VocationService $vocationService, RoleService $roleService)
{
$this->userRepository = $userRepository;
$this->vocationService = $vocationService;
$this->roleService = $roleService;
}
}
There are only three dependencies which I'm injecting.
Assume, I want to add next dependency, for example: NextService.
My constructor will grow again.
What if I wanted to pass more dependencies within constructor ?
Maybe should I solve this problem by passing IoC container and then get desirable class?
Here is an example:
<?php
class UserService{
private $userRepository;
private $vocationService;
private $roleService;
public function __construct(ContainerInterface $container)
{
$this->userRepository = $container->get('userRepo');
$this->vocationService = $container->get('vocService');
$this->roleService = $container->get('roleService');
}
}
But now my UserService class depends on IoC container which I'm injecting.
How to solve a problem following good practices?
Regards, Adam
Injecting the container as a dependency to your service is considered as a bad practice for multiple reasons. I think the main point here is to figure out why and then try to understand the problem that leads you to think about "injecting the container" as a possible solution and how to solve this problem.
In object oriented programming, it's important to clearly define the relations between objects. When you're looking at a given object dependencies, it should be intuitive to understand how the object behaves and what are the other objects it relies on by looking at its public API.
It's also a bad idea to let your object rely on a dependency resolver, In the example you shared your object can't live without the container which is provided by the DI component.
If you want to use that object elsewhere, in an application that uses another framework for example, you'll then have to rethink the way your object get its dependencies and refactor it.
The main problem here is to understand why your service needs all these dependencies,
In object-oriented programming, the single responsibility principle
states that every context (class, function, variable, etc.) should
define a single responsibility, and that responsibility should be
entirely encapsulated by the context. All its services should be
narrowly aligned with that responsibility.
Source: Wikipedia
Based on this definition, I think you should split your UserService into services that handle only one responsability each.
A service that fetch users and save them to your dababase for example
Another service that manages roles for example
... and so on
I agree that __construct can grow fairly easy.
However, you have a Setter DI at your disposal: http://symfony.com/doc/current/components/dependency_injection/types.html#setter-injection
Morover, there is a Property DI, but I wouldn't recommed it as ti leaves your service wide-open to manipulation: http://symfony.com/doc/current/components/dependency_injection/types.html#property-injection
You can abstract some of the commonly used services in one helper service and then just inject this helper into your other services. Also you can define some useful functions in this helper service. Something like this:
<?php
namespace Saman\Library\Service;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Form\FormFactory;
use Symfony\Bundle\FrameworkBundle\Translation\Translator;
use Symfony\Bundle\TwigBundle\Debug\TimedTwigEngine;
use Symfony\Component\Security\Core\SecurityContext;
use Doctrine\ORM\EntityManager;
class HelperService
{
protected $translator;
protected $securityContext;
protected $router;
protected $templating;
protected $em;
public function __construct(
Translator $translator,
SecurityContext $securityContext,
Router $router,
TimedTwigEngine $templating,
EntityManager $em
)
{
$this->translator = $translator;
$this->securityContext = $securityContext;
$this->router = $router;
$this->templating = $templating;
$this->em = $em;
}
Getters ...
public function setParametrs($parameters)
{
if (null !== $parameters) {
$this->parameters = array_merge($this->parameters, $parameters);
}
return $this;
}
/**
* Get a parameter from $parameters array
*/
public function getParameter($parameterKey, $defaultValue = null)
{
if (array_key_exists($parameterKey, $this->parameters)) {
return $this->parameters[$parameterKey];
}
return $defaultValue;
}
}
Now imagine you have a UserService then you define it like this:
<?php
namespace Saman\UserBundle\Service;
use Saman\Library\Service\HelperService;
class UserService
{
protected $helper;
public function __construct(
Helper $helper,
$parameters
)
{
$this->helper = $helper;
$this->helper->setParametrs($parameters);
}
public function getUser($userId)
{
$em = $this->helper->getEntityManager();
$param1 = $this->helper->getParameter('param1');
...
}
This example was created for Symfony 4 but the principle should work in older versions.
As others have mentioned, it's good to engineer your application to limit the functional scope of each service and reduce the number of injections on each consuming class.
The following approach will help if you truely need many injections, but it's also a nice tidy way to reduce boilerplate if you are injecting a service in many places.
Consider a service App\Services\MyService that you wish to inject into App\Controller\MyController:
Create an 'Injector' trait for your service.
<?php
// App\Services\MyService
namespace App\DependencyInjection;
use App\Services\MyService;
trait InjectsMyService
{
/** #var MyService */
protected $myService;
/**
* #param MyService $myService
* #required
*/
public function setMyService(MyService $myService): void
{
$this->myService = $myService;
}
}
Inside your controller:
<?php
namespace App\Controller;
class MyController
{
use App\DependencyInjection\InjectsMyService;
...
public myAction()
{
$this->myService->myServiceMethod();
...
}
...
}
In this way:
a single line of code will make your service available in any container managed class which is super handy if you're using a service in many places
it's easy to search for your injector class to find all usages of a service
there are no magic methods involved
your IDE will be able to auto-complete your protected service instance property and know it's type
controller method signatures become simpler, containing only arguments
If you have many injections:
<?php
namespace App\Controller;
use App\DependencyInjection as DI;
class SomeOtherController
{
use DI\InjectsMyService;
use DI\InjectsMyOtherService;
...
use DI\InjectsMyOtherOtherService;
...
}
You can also create an injector for framework provided services, e.g. the doctrine entity manager:
<?php
namespace App\DependencyInjection;
use Doctrine\ORM\EntityManagerInterface;
trait InjectsEntityManager
{
/** #var EntityManagerInterface */
protected $em;
/**
* #param EntityManagerInterface $em
* #required
*/
public function setEm(EntityManagerInterface $em): void
{
$this->em = $em;
}
}
class MyClass
{
...
use App\DependencyInjection\InjectsEntityManager;
A final note: I personally wouldn't try to make these injectors any smarter than what I've outlined. Trying to make a single polymorphic injector will probably obfuscate your code and limit your IDE's ability to auto-complete and know what type your services are.
I want to override the timestamps() function found in the Blueprint class. How can I do that?
e.g.,
public function up() {
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('username')->unique();
$table->string('password');
$table->string('email');
$table->string('name');
$table->timestamps(); // <-- I want this to call my method instead of the one found in the base Blueprint class
});
}
There is a new blueprintResolver function which takes a callback function which then returns the Blueprint instance.
So create your custom Blueprint class like this:
class CustomBlueprint extends Illuminate\Database\Schema\Blueprint{
public function timestamps() {
//Your custom timestamp code. Any output is not shown on the console so don't expect anything
}
}
And then call the blueprintResolver function where you return your CustomBlueprint instance.
public function up()
{
$schema = DB::connection()->getSchemaBuilder();
$schema->blueprintResolver(function($table, $callback) {
return new CustomBlueprint($table, $callback);
});
$schema->create('users', function($table) {
//Call your custom functions
});
}
I'm not sure if creating a new schema instance with DB::connection()->getSchemaBuilder(); is state of the art but it works.
You could additionally override the Schema facade and add the custom blueprint by default.
Marcel Gwerder's answer was a life saver. Like some of the users commented there, I wondered if this could be done more automagically. My goal was similarly to overwrite the timestamps method. After some tinkering, this is what I ended up with which is working for me:
I created a file at app/Classes/Database/Blueprint.php:
<?php
namespace App\Classes\Database;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Schema\Blueprint as BaseBlueprint;
class Blueprint extends BaseBlueprint
{
/**
* Add automatic creation and update timestamps to the table.
*
* #param int $precision
*/
public function timestamps($precision = 0): void
{
$this->timestamp('created_at', $precision)->default(DB::raw('CURRENT_TIMESTAMP'));
$this->timestamp('updated_at', $precision)->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
}
}
I created a file at app/Facades/Schema.php
<?php
namespace App\Facades;
use App\Classes\Database\Blueprint;
use Illuminate\Database\Schema\Builder;
use Illuminate\Support\Facades\Schema as BaseSchema;
class Schema extends BaseSchema
{
/**
* Get a schema builder instance for a connection.
*
* #param string|null $name
* #return Builder
*/
public static function connection($name): Builder
{
/** #var \Illuminate\Database\Schema\Builder $builder */
$builder = static::$app['db']->connection($name)->getSchemaBuilder();
$builder->blueprintResolver(static function($table, $callback) {
return new Blueprint($table, $callback);
});
return $builder;
}
/**
* Get a schema builder instance for the default connection.
*
* #return Builder
*/
protected static function getFacadeAccessor(): Builder
{
/** #var \Illuminate\Database\Schema\Builder $builder */
$builder = static::$app['db']->connection()->getSchemaBuilder();
$builder->blueprintResolver(static function($table, $callback) {
return new Blueprint($table, $callback);
});
return $builder;
}
}
Inside config/app.php I updated the alias for Schema as follows:
'aliases' => [
'Schema' => App\Facades\Schema::class,
],
Now, in my migrations, like the below, when I call timestamps(), it calls my overwritten method.
<?php
use App\Classes\Database\Blueprint;
use \Illuminate\Database\Migrations\Migration;
class TimestampTest extends Migration
{
/**
* Run the migrations.
*
* #return void
* #throws \Throwable
*/
public function up(): void
{
Schema::connection('mysql')->create('some_table', static function (Blueprint $table) {
$table->string('some_column')->nullable();
$table->timestamps();
});
}
// ....
}
I likewise wanted to solve this in an "automagic" way, so took inspiration from #WesleySmith's answer to implement a solution that involved overriding the base Schema facade that returns a customised Blueprint class.
However, as of Laravel 9, the protected static function getFacadeAccessor() method is now expected to return a string only, representing a lookup key in the service container. This change is documented in the Laravel 9 upgrade guide (search for "getFacadeAccessor"), and here's the relevant commit to the framework that made this alteration. The upgrade guide has this to say:
The getFacadeAccessor method must always return a container binding key. In previous releases of Laravel, this method could return an object instance; however, this behavior is no longer supported. If you have written your own facades, you should ensure that this method returns a container binding string.
For the Schema facade, this container binding key is the string db.schema (as seen here, although it hasn't been documented in the Facade Class Reference in the Laravel documentation yet).
Therefore my Schema class dispenses with the customised getFacadeAccessor method and relies on the parent class to return the db.schema key, and provides the logic for creating a custom schema builder using a static customizedSchemaBuilder method.
class Schema extends BaseSchema
{
/**
* Get a schema builder instance for a connection.
*
* #param string|null $name
*
* #return Builder
*/
public static function connection($name): Builder
{
return static::customizedSchemaBuilder($name);
}
/**
* Retrieves an instance of the schema `Builder` with a customized `Blueprint` class.
*
* #param string|null $name
*
* #return Builder
*/
public static function customizedSchemaBuilder(string|null $name = null): Builder
{
/** #var Builder $builder */
$builder = static::$app['db']->connection($name)->getSchemaBuilder();
$builder->blueprintResolver(static fn($table, $callback) => new CustomBlueprint($table, $callback));
return $builder;
}
}
The logic to resolve the customised Builder that was previously in getFacadeAccessor should instead be included in your AppServiceProvider's register method:
/**
* #return void
*/
public function register()
{
$this->app->bind('db.schema', fn() => Schema::customizedSchemaBuilder());
}
You should now be able to use your customised Schema facade and Blueprint classes in your migrations using Laravel 9.
Just to add a few points to Marcel Gwerder's answer (which is already great):
You can shorten DB::connection()->getSchemaBuilder() to DB::getSchemaBuilder() because Laravel automagically forward the method call to the connection instance.
Each call to the Schema Facade already creates a new Schema\Builder instance, as can be seen in the getFacadeAccessor() method in the following files:
Support/Facades/Schema.php - Laravel 4.2
Support/Facades/Schema.php - Laravel 5.0-dev
(edit 2016-03-06)A GitHub issue has been recently opened about this: #12539.
I am currently looking a this piece of code from a module called ZfcUser for Zend 2:
namespace ZfcUser\Controller;
use Zend\Form\Form;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Stdlib\ResponseInterface as Response;
use Zend\Stdlib\Parameters;
use Zend\View\Model\ViewModel;
use ZfcUser\Service\User as UserService;
use ZfcUser\Options\UserControllerOptionsInterface;
class UserController extends AbstractActionController
{
/**
* #var UserService
*/
protected $userService;
.
.
public function indexAction()
{
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('zfcuser/login');
}
return new ViewModel();
}
.
.
}
In the namespace ZfcUser\Controller\Plugin:
namespace ZfcUser\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use ZfcUser\Authentication\Adapter\AdapterChain as AuthAdapter;
class ZfcUserAuthentication extends AbstractPlugin implements ServiceManagerAwareInterface
{
/**
* #var AuthAdapter
*/
protected $authAdapter;
.
.
/**
* Proxy convenience method
*
* #return mixed
*/
public function hasIdentity()
{
return $this->getAuthService()->hasIdentity();
}
/**
* Get authService.
*
* #return AuthenticationService
*/
public function getAuthService()
{
if (null === $this->authService) {
$this->authService = $this->getServiceManager()->get('zfcuser_auth_service');
}
return $this->authService;
}
My Questions:
From indexAction(), the controller plugin is called without being instantiated ($this->zfcUserAuthentication()->hasIdentity()), do controller plugins always work like this?.
What really happens in the hasIdentity()? I see getAuthService() returning something but not hasIdentity().I am not familiar with this type of advanced class implementation of function calling so I would truly appreciate any explanation here or topic I should look into.
I can't answer your first question, but regarding your second question:
The getAuthService() method in your code returns an AuthenticationService object, which has a hasIdentity() method.
So there are two different hasIdentity() methods:
In the AuthenticationService class (source code here).
In the ZfcUserAuthentication class which you're looking at.
This line of code in the ZfcUserAuthentication class:
return $this->getAuthService()->hasIdentity();
does three things:
$this->getAuthService() returns an AuthenticationService object.
The hasIdentity() method of that AuthenticationService object is then called, and it returns a boolean.
That boolean is then returned.
Imagine splitting the code into two parts:
// Get AuthenticationService object Call a method of that object
$this->getAuthService() ->hasIdentity();
Hope that helps!
All sorts of plugins in Zend Framework are managed by plugin managers, which are subclasses of AbstractPluginManager which is subclasss of ServiceManager.
$this->zfcUserAuthentication() proxies by AbstractController to pluginmanager internally.
AuthenticationService::hasIdentity() checks if something was added to storage during successful authentication attempt in this or previous request:
See here