I am attempting to add custom repsitories (contract and Eloquent) in Laravel.
I don't understand where to add them and how to bind with services.
Can any body show the best example for add own wn repository class and interfaces in Laravel?
Thanks in advance
Create a directory in your App folder.Like - App/Acme
Create a Repository File in Acme folder. App/Acme/CustomRepository.php and also import the name space on that Repository file.Like- namespace Acme;
Use your model. Like- use App\Models\User;
In you controller inject the CustomRepository Class.Like-
class CustomController extends Controller{
private $customRepo;
public function __construct(CustomRepository $customRepo)
{
$this->customRepo= $customRepo;
}
}
The way I like to structure my Laravel Code would be:
Models - App\Models\*
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as BaseModel;
class Model extends BaseModel
{
//
}
Contracts - App\Repositories\Contracts\*
<?php
namespace App\Repositories\Contracts;
interface Repository
{
// All the common methods for eloquent like - all, paginate, find, where, etc...
}
Repository - App\Repositories\Db\*
<?php
namespace App\Repositories\Db;
class ExampleRepository
{
// All the CRUD related methods here...
}
Services - App\Services\*
<?php
namespace App\Services;
class ExampleService
{
// All the logic & business related methods here...
}
This is what I like to structure my code in a laravel way.
Hope this helps!
For make usage of repository pattern (if it is that what you want to say), you have two options, one of it is to implement under a self-defined namespace (let's say App\Repositories), an interface with the methods you want to use in all your repositories, maybe AbstractRepository or something like that, this one choice is painful because of the lot of code you have to write, the other choice (what I would use), is to install the following package https://github.com/andersao/l5-repository, is really useful and already have inside a lot of methods, just follow the instructions of the readme file and you will not have any issue at all implementing this pattern, hope it helps, bests! ;)
Related
I'm developing a package which has controllers in it and I want this package to be compatible with (or useable by) both Laravel and Lumen projects. My problem is Laravel controllers extend Illuminate\Routing\Controller and Lumen controllers extend Laravel\Lumen\Routing\Controller. The controller inside my package can't extend them both.
The only solution I've come up with is to have the controllers inside the package extend App\Http\Controllers\Controller.
But I see some problems:
App\Http\Controllers\Controller should exist; which means it wouldn't work if the App namespace is named differently.
The package is now "aware" that it is being included in something.
Testability: I can't test the controller independently because of the reference to App\Http\Controllers\Controller.
Is there a better way of doing this?
Edit 1
I'm finding other classes which are affected in a similar way. For example, the namespace of the trait Authorizable is Illuminate\Foundation\Auth\Access in Laravel while it is Laravel\Lumen\Auth in Lumen. I am using a model which uses that trait. How do I make my model compatible with both Lumen and Laravel?
Well, you could simply have two different files and classes wrapped in if statements and check for the corresponding classes to extend. So:
LaravelClass.php:
if(class_exists(Illuminate\Routing\Controller:class)){
class LaravelClass extends Illuminate\Routing\Controller {
use YourCodeTrait;
// any more code that is not in your trait
}
}
LumenClass.php
if(class_exists(Laravel\Lumen\Routing\Controller:class)){
class LaravelClass extends Laravel\Lumen\Routing\Controller {
use YourCodeTrait;
// any more code that is not in your trait
}
}
Loading both files will only load one of the classes. In the code above I use a trait to load the contents of your controller, assuming the contents is the same, you could use the same trait and not have to repeat yourself.
trait YourCodeTrait{
// whatever would normally go in your controllers
}
I have started with YII2 just today. i have installed it successfully and also created required Model, Controllers & views in that using CRUD.
Now my question is as below:
I want to create one Global Validator Rule which we can use in throughout the Models in system.
What i have tried so far:
For that i have created one new model file(FormValidator) in common folder and generate one custom rule method in it.
common/model/FormValidator.php
namespace common\models;
use Yii;
use yii\base\Model;
class FormValidator extends \yii\db\ActiveRecord {
}
then i tried to extend this model file to my frontend model file. but its not working.
frontend/model/Customerprofile.php
namespace frontend\models;
use Yii;
use common\models\FormValidator;
class Customerprofile extends FormValidator{
}
It's throw below error message:
PHP Fatal Error – yii\base\ErrorException
Class 'common\models\FormValidator' not found
I don't know what i have missing in all these process, if anyone of you help me out from this, would be much appreciated!
Thanks in Advance.
If you want to extend some master class for model you have to simply extend CActiveRecord and then your models will extend this masterclass.
I am very new to "Advanced Laravel" so to speak, however I do know most of the basics and I am trying to understand what namespacing, interfaces and repositories is all about, since I came across it not so long ago.
However, I am getting the following error, and I have no idea what I am doing wrong:
Class app\models\Interfaces\CategoriesInterface does not exist
Below is my code:
Routes.php
App::bind('App\Models\Interfaces\BaseInterface', 'App\Models\Repositories\BaseRepository');
CategoriesController.php
<?php
use app\models\Interfaces\CategoriesInterface;
class CategoriesController extends BaseController
{
protected $categories;
public function __construct(CategoriesInterface $categories)
{
$this->categories = $categories;
}
BaseInterface.php
<?php
interface BaseInterface
{
public function all();
}
CategoriesInterface.php
<?php namespace App\Models\Interfaces;
interface CategoriesInterface extends BaseInterface { }
CategoriesRepository.php
<?php namespace app\models\Repositories;
use App\Models\Interfaces\CategoriesInterface;
use Categories;
class CategoriesRepository implements CategoriesInterface
{
public function all()
{
$categories = $this->categories->all();
return $categories;
}
}
EloquentCategoriesRepository.php
<?php namespace app\models\Repositories;
use App\Models\Interfaces\CategoriesInterface;
class EloquentCategoriesRepository implements CategoriesInterface {
public function all()
{
return Categories::all();
}
Try name spacing the classes/interfaces properly. EloquentCategoriesRepository.php and CategoriesRepository are having app instead of App in the namespace. And CategoriesController too needs to use App\.. not app\...
I see you are trying to implement the repository pattern, which at first it might seem a bit 'advanced' but it's actually pretty simple.
So the basic idea is to abstract the data layer of your application with the database to make your transitions from one DBS to another(ex. Mysql to Mongo).
In other words your are trying to make the business logic of your application independent to the data layer (Where you query your collections/instances), so when you reach a point that you might want to change your database you can just implement another repository. The Interfaces are there to provide a contract between your application and the data layer.
Laravel implementation of the repository pattern it's pretty straight forward.
Create your interface
Create your interface's repository (actual implementation)
Bind the repository using a service provider class (Or in your case App::bind)
Instantiate the dependency in to your controller using the repository
Don't forget to auto load your namespaces using psr-04.
In your case I think the problem is you are not autoloading the namespace.
Also CategoriesRepository.php & EloquentCategoriesRepository.php are both Eloquent repositories and will return Eloquent collections. To return an array of stdClass (standar PDO) you will have to use the \DB facade.
If my answer does not cover you please take a look here
We are looking to build a system with core classes and the ability to extend these core classes and are looking in to using namespaces.
The problem we are having is working out if we can extend an extended class without extending the class that it extends from
For example, if we have folders and files as below
shared/classes/Entity.php
shared/classes/DatabaseEntity.php - Extends Entity.php
shared/classes/User.php - Extends DatabaseEntity.php
classes/ - Holds classes which extend from the shared classes
If we wanted to create a custom DatabaseEntity class without creating a custom User class , is this possible?
The way I understand this is that the User class will be looking in the shared namespace to extend the DatabaseEntity class but as we have extended the DatabaseEntity class, it needs to look at the top level classes directory
Example of shared/classes/User.php
namespace shared;
class User extends DatabaseEntity {
}
Example of shared/classes/DatabaseEntity.php
namespace shared;
abstract class DatabaseEntity extends Entity {
}
Example of classes/DatabaseEntity.php
namespace custom;
use shared\classes\Entity;
abstract class DatabaseEntity extends Entity {
//Some custom functionality to extend shared/DatabaseEntity
}
So if we didn't want to change the User class to say
use custom/DatabaseEntity
Then is this possible?
Hopefully that makes sense
Thanks in advance for any help
If you don't want to add to User class
use custom/DatabaseEntity
and you want to extend custom/DatabaseEntity
you may just change class declaration from
namespace shared;
class User extends DatabaseEntity {
}
to
namespace shared;
class User extends \custom\DatabaseEntity {
}
if you want to extend \custom\DatabaseEntity.
If it's not want you want to achieve I cannot understand your problem - you ask two questions.
You asked
If we wanted to create a custom DatabaseEntity class without creating
a custom User class , is this possible?
The answer is - yes, you just created it in your example. You created custom DatabaseEntity class without creating custom User class.
But if you want to achieve:
it needs to look at the top level classes directory
you need to tell User class to extend specific class - so you will need to extend using fully qualified class or import namespace using use and creating alias
I don't know if I understand you well, but you want to create CustomDatabaseEntity class that will extend DatabaseEntity and you don't want that CustomDatabaseEntity extends User class.
It's of course possible. You can create as many child classes as you want. As User class is defined that it extend DatabaseEntity class it will even don't know that you created CustomDatabaseEntity
I also think that you are using it a bit wrong. If DatabaseEntity have anything common with database and not with User itself, you should rather create Interface DatabaseEntityInterface, those two DatabaseEntity classes should implement interface
and then in User class you should pass it as constructor argument
class User {
protected $dbi;
public function _construct(DatabaseEntityInterface $dbi) {
$this->dbi = $dbi
}
}
and later you can pass to User class either class for shared folder or the one from classes
I am working on a php sdk rewrite project and the client wants to get PSR standards done. I am looking at the standards page here
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
One thing what i am not able to understand, if i use name spaces in my class do i still need to use include or require or use. I mean the whole reason of autoload beats the purpose right ?
For example, say i have a class this way,
namespace Employee\Department;
Class Department
{
//code
}
and i have another class which uses this class by extending it,
namespace Employee\community;
Class Community extends Department
{
//code
}
so does the above code make it to psr-0 standard considering that i have an autoload function exactly thats on the link above.
The second example is going to assume Department is in the Community namespace so in this case you would need a use statement. Also both of your examples would use the namespace Employee not Employee\Whatever for example lets assume the following layout:
Employee/
Community.php
Community/
Manager.php
Department.php
Department/
Manager.php
Then we would see the class/namespaces like the following
namespace Employee;
class Department {
}
///////////
namespace Employee;
class Community extends Department {
}
/////////////
namespace Employee\Department;
class Manager {
}
/////////////
namespace Employee\Community;
use Employee\Department\Manager as BaseManager;
Class Manager extends BaseManager {
}
For your understanding, autoloading works by registering the autoload function in the autoload stack via spl_autoload_register; this allows the function to be invoked whenever a new Class() statement is executed (more info).
On the other hand, the FIG standard for autoloading, PSR-0, defines how a namespace will be translated into a filename by a PSR-0 autoloader function. For example, given the namespace Vendor\Foo, the autoloader will look for the file Vendor/Foo.php having the following code
namespace Vendor;
class Foo
{
public function do()
{
echo "Foo";
}
}
Therefore, following the mandatory requirements, a PSR-0 compliant namespace resolves to the correct PHP file which could otherwise have been included using a require or include.
If I read your intentions correctly, you just need the following namespace in both code snippets:
namespace Employee;
Of course, this is not a PSR-0 namespace because there is no vendor name (unless your vendor name is 'Employee'). Anyway, using this namespace in your two code snippets will work fine.
However, if you intended to keep them in separate namespaces, then the autoloader won't figure out Department in extends Department in the second snippet. You will have to either import the namespace or explicitly specify it as so:
namespace Employee\community;
class Community extends Employee\Department\Department
{
//code
}
I imagine that you did not expect the full class names from your snippets to be Employee\Department\Department, and that is why I first suggested keeping the same namespace for your purposes.