I try defined property for some controller and i get error :
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_UNKNOWN)
Constant expression contains invalid operations
This my controller code :
namespace App\Http\Controllers...;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Customer;
use App\City;
use Illuminate\Database\Eloquent\Builder;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
class CatalogController extends Controller
{
protected $user = Auth::user();
function user() {
$user = optional(Auth::user())->load(['city']);
return $user;
}
}
In php.net I read this:
Class member variables may be initialized, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
I assume that this rule is not executed in my code. Am I right?
Retrieving the user in a controller method is fine because it is only executed once for the request. There is no need to advantage to storing it as instance property because a new instance of the controllers is made for every request.
You could use the following code:
public function index()
{
$user = Auth::user()->with('city')->get();
$articles = $this->getArticlesForUser($user);
return view('home', [
'user' => $user
]);
}
public function getArticlesForUser(User $user){
// Do something with $user
return [];
}
public function delete()
{
$user = Auth::user();
$user->delete();
return view('home');
}
If the goal is to have calculate the values once and use them at various places a singleton can be used:
<?php
class Settings {
private $accessToken = '';
private $items = [];
private static $instance = null;
protected function __construct(){}
public static function getInstance(){
if(static::$instance == null){
static::$instance = static::buildInstance();
}
return static::$instance;
}
private static function buildInstance(){
$instance = new Settings();
$instance->accessToken = md5(rand(1,1000));
$instance->items = [1,2,3];
return $instance;
}
public function getToken(){
return $this->accessToken;
}
}
$settings = Settings::getInstance();
// Both return the same token because the instance is the same
var_dump($settings->getToken());
var_dump(Settings::getInstance()->getToken());
You should assign your properties in constructor like this
protected $user;
public function __construct()
{
$this->user = Auth::user();
}
or through setters...
Edit
However in your case it's not a good idea please see https://laravel.com/docs/5.3/upgrade#5.3-session-in-constructors
Related
My error in line 21
I have imports:
use Maatwebsite\Excel\Concerns\FromCollection;
use App\Models\EmployeeInCompany;
use Auth;
use Maatwebsite\Excel\Concerns\Exportable;
And my Export Folder : ReportExport
class ReportExport implements FromCollection
{
use Exportable;
protected $request;
public function __construct($request)
{
$this->request = $request;
}
public function collection()
{
if ($this->request->has('filter_date')) {
$employee = EmployeeInCompany::where('company_id', Auth::user()->company_id)->get();
}else{
$employee = EmployeeInCompany::where('company_id', \Session::get('selected_company'))->get();
}
}
}
I made an export to excel. I use the code in the public function __construct to hold the $request variable for the date filter. how to solve my problem? help me, thanks.
2 options to handle this:
You can pass the request to your constructor in ReportController.php (make sure $request is defined):
new ReportExport($request);
or you can remove the parameter in the constructor and use the request helper function:
public function __construct()
{
$this->request = request();
}
I am following this link to implement it
I did below steps to implement the Contract in my existing class.
Below is the class where I will write some logic also before sending it to controller
namespace App\Classes\BusinessLogic\Role;
use App\Classes\DatabaseLayer\Role\RoleDb;
use App\Classes\Contract\Role\IRole;
class RoleBL implements IRole {
public function All() {
return (new RoleDb())->All();
}
}
Database Function
namespace App\Classes\DatabaseLayer\Role;
class RoleDb {
public function All() {
$Roles = \App\Models\Role\RoleModel
::all();
return $Roles;
}
}
Interface
namespace App\Classes\Contract\Role;
interface IRole {
public function All();
}
Service Provider class
namespace App\Providers\Role;
class RoleServiceProvider extends \Illuminate\Support\ServiceProvider {
public function register()
{
$this->app->bind('App\Classes\Contract\Role\IRole', function($app){
return new \App\Classes\BusinessLogic\Role\RoleBL($app['HttpClient']);
});
}
}
Finally in config/app.php in provider wrote below line.
App\Providers\Role\RoleServiceProvider::class
Controller - Constructor
protected $roles;
public function __construct(\App\Classes\Contract\Role\IRole $_roles) {
parent::__construct();
$roles = $_roles;
}
Controller Action method
public function index(IRole $roles) {
$RoleTypes = $roles->All();
}
So far everything works fine if I keep Interface as parameter in method.
if I try to use the variable $roles in index method and remove the variable, it is always null.
Please guide me if I missed anything?
You incorrectly assign the $roles property in your __construct() method.
Replace
$roles = $_roles;
with
$this->roles = $_roles;
and then in your index method do:
$RoleTypes = $this->roles->All();
I'm writing a new project with laravel 5.1, and I want to use the repository pattern, but I can't figure out what is the best way of doing that.
I was thinking about:
public function save(User $user)
{
$user->save();
}
public function find($id)
{
return User::find($id);
}
And then
$user = new User();
$user->email = 'foo#bar.com';
$userRepo->save($user);
That way I work with the model as DTO, and it's super easy and comfortable, but then I will be depend on Eloquent.
So I was thinking of using an array instead of model, like that:
public function save(array $user)
{
User::save($user);
}
public function find($id)
{
return User::find($id)->toArray();
}
But then it will be much less comfortable to use.
Can you explain me what is the best way of using repository in Laravel so I will be able to change data source easily in the future, but it will still be comfortable to use this pattern?
I have it set up as follows, using your example:
<?php namespace Repositories;
use Models\User;
class UserEloquentRespository implements UserInterface {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function create($input)
{
$this->user->create($input);
}
}
Then in my controller
Laravel 4
<?php namespace Controllers;
use Repositories\UserInterface as User;
class UsersController extends \BaseController {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function store()
{
$input = \Input::all();
// validation here
// now create your user
$user = $this->user->create($input);
if ($user) {
// redirect or do whatever you do on successful user creations
}
// Here you can do whatever you do if a user wasn't created for whatever reason
}
}
Laravel 5
<?php namespace App\Http\Controllers;
use Repositories\UserInterface as User;
use App\Http\Requests\UserRequestForm;
use App\Http\Controllers\Controller;
class UsersController extends Controller {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function store(UserRequestForm $request)
{
// Form request validates in middleware
// now create your user
$user = $this->user->create($request->input());
if ($user) {
// redirect or do whatever you do on successful user creations
}
// Here you can do whatever you do if a user wasn't created for whatever reason
}
}
Lastly, don't forget to bind your interface to your eloquent repository as a service provider.
App::bind(
'Repositories\UserRepositoryInterface',
'Repositories\Eloquent\UserEloquentRepository'
);
Now, whenever you need to change your implementation just change the binding to whatever new class implements your interface.
I have a class in Laravel with a class variable that holds and object
class RegisterController extends Controller {
public $company;
When i set the variable in my index method all goes well
public function index($id = null) {
$this->company = new Teamleader\Company;
When I try to access $this->company from another method it returns
null
This is my full code
class RegisterController extends Controller {
public $company;
public function index($id = null)
{
$this->company = new Teamleader\Company;
// returns ok!
dd($this->company);
return view('register.index');
}
public function register()
{
// returns null
dd($this->company);
}
}
Am I missing something?
Thank you!
You are not __constructing() the class, you are just assigning variable inside a function inside a class, which means it is encapsulated into that function inside that class.
So if you would like to make $this->company global in class, you could use
public function __construct() {
$this->company = new Teamleader\Company;
}
In Laravel 5 you can inject a new instance of Teamleader\Company into the methods you need it available in.
use Teamleader\Company;
class RegisterController extends Controller {
public function index($id = null, Company $company)
{
dd($company);
}
public function register(Company $company)
{
dd($company);
}
}
For Laravel <5 dependency inject into the constructor.
use Teamleader\Company;
class RegisterController extends Controller {
protected $company;
public function __construct(Company $company)
{
$this->company = $company;
}
public function index($id = null)
{
dd($this->company);
}
public function register()
{
dd($this->company);
}
}
Dependency injection is better than manual invocation as you can easily pass a mock object to this controller during testing. If you're not testing, maybe someone else will be in the future, be kind. :-)
I am trying to test my controller with this test (I'm using Laravel, if that matters):
<?php
use Zizaco\FactoryMuff\Facade\FactoryMuff;
class ProjectControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->mock = $this->mock('Dumminvoicing\Storage\Project\ProjectRepositoryInterface');
}
public function mock($class)
{
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
protected function tearDown()
{
Mockery::close();
}
public function testRedirectWhenNotLogged()
{
Route::enableFilters();
$response = $this->call('GET', 'projects');
$this->assertRedirectedToAction('UserController#getLogin');
}
public function testAllowedWhenLogged()
{
Route::enableFilters();
//Create user and log in
$user = FactoryMuff::create('User');
$this->be($user);
$response = $this->call('GET', 'projects');
$this->assertResponseOk();
}
public function testIndex()
{
$this->mock->shouldReceive('all')->once();
$this->call('GET', 'projects');
$this->assertViewHas('projects');
}
}
Following these tutorials http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories/ http://culttt.com/2013/07/15/how-to-structure-testable-controllers-in-laravel-4/ I use repositories to avoid coupling my DB to the tests. So I have these 2 extra classes:
<?php
namespace Dumminvoicing\Storage\Project;
use Project;
class EloquentProjectRepository implements ProjectRepository
{
public function all()
{
return Project::all();
}
public function find($id)
{
return Project::find($id);
}
}
<?php
namespace Dumminvoicing\Storage\Project;
interface ProjectRepository
{
public function all();
public function find($id);
}
When I run the test, I get this error:
There was 1 error:
1) ProjectControllerTest::testIndex
Mockery\Exception\InvalidCountException: Method all() from Mockery_2143809533_Dumminvoicing_Storage_Project_ProjectRepositoryInterface should be called
exactly 1 times but called 0 times.
The index method of the controller works fine in the browser:
use Dumminvoicing\Storage\Project\ProjectRepository as Project;
class ProjectsController extends \BaseController
{
protected $project;
public function __construct(Project $project)
{
$this->project = $project;
$this->beforeFilter('auth');
}
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$data['projects'] = $this->project->all();
return View::make('projects.index', $data) ;
}
So why is it failing in the test? Why is "all" not being called?
If the user has to be authenticated to hit the index method, you need to authenticate each test.
The all isn't getting called because the user is being redirected.
Create an authentication method that you can call each time you need to authenticate the request.
To see why the test failing, dump out the response before you do the assert.
Edit
The problem is you've mocked Dumminvoicing\Storage\Project\ProjectRepositoryInterface but it should be Dumminvoicing\Storage\Project\ProjectRepository.
If you correct the namespace and add $this->mock->shouldReceive('all')->once(); to the testAllowedWhenLogged() method your tests will pass correctly.