The Laravel documentation states that you can register a model server in a service provider, however it says nothing in the way of how that is done that I have seen. All of my searches through google have turned up nothing useful. I attempted to write some code like this:
namespace name;
use /path/to/ServiceProvider;
use path/to/UserObserver;
class UserObserverServiceProvider extends ServiceProvider{
public function boot(){
User::observe(new UserObserver);
}
public function register{}
}
}
which was the only suggestion that implied it should work I could find in my searches, however, it says the User class is not found when i attempt to run it. I tried to put a path to the User model, but it doesn't recognize the models directory as a path to anything...
hoping someone can help clear this up for me.
figured out that the names of the model classes were all that was needed to specify the path in the use command, it works now, I just had to specify
use User;
Related
I have a question maybe a little silly. I'm trying to replicate and store a model instance in a variable to call the loadMissing method. The idea is to call the loadMissing method without being affected by the original model. Let me explain.
I have the following method in my User model:
class User extends Authenticatable
{
...
public function myCustomMethod()
{
$cloned = $this->replicate()
->loadMissing(['roles', 'roles.permissions'])
->getAttribute('roles')
->flatMap(function ($role) {
return $role->permissions
});
return $cloned;
}
The problem is that in this way the original model instance is affected, and it loads in the original instance all the relations that I am loading only in this method.
My question is: is there a way to load and isolate relationships in a replica of the model instance without affecting the original model?
Thanks in advance.
EDIT 1
I have also tried cloning the instance and trying to use the loadMissing method on the cloned instance, but the original instance is also affected. For example:
class User extends Authenticatable
{
...
public function myCustomMethod()
{
$original = $this;
$cloned = clone $original;
$cloned->loadMissing('roles.permissions');
dump($original);
dump($cloned);
die();
}
But in this way, I get the following results. Notice that both the original and the cloned instance are loading the relationships when I'm just trying to load the relationships in the cloned instance:
$original
$cloned
I was wondering if this is normal behavior. If it is a normal behavior, which I suppose it is not, I was wondering if there is any way to use the loadMissing method on a copy, replica or clone of an instance without modifying the original instance. Thank you very much in advance.
EDIT 2
My controller looks like simple like this:
class HomeController extends Controller
{
public function index()
{
dd(User::find(1)->myCustomMethod());
}
}
SOLUTION
After several days looking for documentation, doing tests and pulling my hair a little, I have found the solution to my problem and share it in case someone comes here looking for similar information in the future.
Basically the answer that helped me find the right way was this:
https://stackoverflow.com/a/29787693/13066106
Which is documented in the official PHP documentation:
https://www.php.net/manual/en/language.oop5.cloning.php
I copy and paste verbatim the most relevant here:
When an object is cloned, PHP will perform a shallow copy of all of the object's properties. Any properties that are references to other variables will remain references.
When I got to this point, I understood why it wasn't working ... I was cloning a collection of type Illuminate\Database\Eloquent\Collection and this collection contained multiple objects of type Role, but according to the documentation, it is normal behavior that when I modify any property in the cloned instance, the changes will be reflected back to me in the original instance.
From here, I looked for more documentation about it and I found an article that definitely helped me solve my problem:
Don't clone your php objects, DeepCopy them
The article is quite descriptive and basically what it does is advise the use of the package DeepCopy
Fortunately, the package is already a Laravel dependency by default, so I didn't have to install it with composer. I just used the deep_copy method to clone the instance.
Thank you very much to everyone who helped me in some way. I hope that the links to the documentation that I have shared will be of use to those who come here looking for similar information.
Why don't you just get the permissions collection (outside of model):
$userId = $user->id;
$premissions = Permissions::whereHas('users', function($userQuery) use ($userID) {
$userQuery->where('id',$userId);
})
->get();
Or do the flatmap:
$result = Roles::with('permissions')
->whereHas('users', function($userQuery) use ($userID) {
$userQuery->where('id',$userId);
})
->get()
->flatMap(function ($role) {
return $role->permissions
});
I would like to more in depth knowledge about using static methods . I'm using laravel 5.2 framework for my application.
In my application mostly i have used static functions For example i have model class name like post and method name is get_post() and its declared as static only if i missed static keyword in laravel it throws error
class Post extends Eloquent(){
public static function get_post(){
return DB::table('post')->get();
}
}
In my controller i will call this above method
Post::get_post()
How could i avoid to call this method as static ? as per the PHPMD 1.4.0 rule
Anyone please explain clearly.
Laravel's Eloquent is called via the static method, so I'm not sure how to avoid this. By the way, instead of the functions you wrote, you can of course write
Post::all();
Another abstraction possibility is to use the Repository Pattern, where the Controller doesn't call the Model's functions directly, but rather something like
$activePosts = $postRepository->getActiveAndApproved();
where the $postRepository would do some of the heavy lifting on Laravel's Eloquent model doing e.g. ->where('something', true) and stuff like that - Symfony has this already a bit stronger included in their framework.
See https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more detailed instructions.
Seeing also that Laravel uses Facades a lot, which is a simplified way to access functions in the service container (e.g. see config/app.php or https://laravel.com/docs/5.2/facades for more infos), it might be difficult to avoid static function calls.
I am not sure if I am going about this the right way but here is what I am attempting to do, if there is a better way please let me know.
I am using a service provider that pulls some data from a config file. the problem is that if I use Config::set to change one of the settings after calling a function that uses that service provider it will not update. I thought that because I am using app->bind instead of app->share that it would re instantiate the class every time. here is my code:
service provider:
public function Register() {
$app = $this->app;
$app->bind('\path\to\MyInterface', function() use($app) {
$server = $app['config']->get('myconfig.server');
$client = $app['config']->get('myconfig.client');
$key = $app['config']->get('myconfig.key');
$version = $app['config']->get('myconfig.version');
return new MyService(new Instance($server, $client, $key, $version));
});
$this->app->booting(function() {
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('MyServiceFacade', '\path\to\MyFacade');
});
}
Facade class:
class MyServiceFacade extends Facade {
protected static function getFacadeAccessor() { return '\path\to\MyInterface'; }
}
route for testing:
Route::get('test', function() {
$nodes = MyServiceFacade::allNodes();
\Config::set('myconfig.server', 'new server name');
$nodes2 = MyServiceFacade::allNodes();
var_dump($nodes->getContent());
var_dump($nodes2->getContent());
}
);
I am getting the same results from both. shouldn't this be using the update config since I am making a new instance of the controller?
Skip to update 2 below for a stab at the answer
Your question doesn't quite make sense. In your testing route you're saying
App::make('MyController');
This is you asking Laravel to make an instance of the MyController service and/or class. However, you never define a MyController service and/or class.
You bind a \pathto\Interface identifier here
$app->bind('\pathto\Interface', ...
and alias MyService to that identifier here
$loader->alias('MyService', '\pathto\Facade');
but there's no place you bind or alias a MyController identifier anywhere. There's nothing in your code samples that tie MyController to the service you have bound.
Because of that it's not 100% clear what you're asking.
Update: Your question still doesn't quite make sense, and I think this not-sense-masking is what's leading the the unexpected behavior. i.e., you're doing something that "works", as in PHP doesn't complain with an error, but what you think is happening behind the scenes is not happening.
You've refereed to MyService as a facade -- however, you haven't told us what the "facade accessor" string the MyService facade points to (via its getFacadeAccessor method). Also, you appear to be directly instantiating a class from that facade class (new MyService), which isn't how Laravel facades work.
Update 2: The code samples provided are still a little sketchy, and I suspect they don't accurately reflect the actual application. The context from the comments are that MyServiceFacade::allNodes is a call to a facade. However, the facade defined in the code samples is named MyFacade and there's no class MyServiceFacade. I'm going to take a stab based on something mentioned in a comment as to the problem, but based on what I've seen above the problem still might be an incorrect application of service providers, services, and facades.
Binding a service with bind ensures the application container will always return a new instance of the service. I bet if you tried something like the following
$app = app();
$object = $app['\path\to\MyInterface'];
You'd find your object is instantiated anew every time. Adding some basic var_dump debugging to the bound closure and/or service class constructor is a good way to confirm that.
However, Laravel facades are a little different. They're not, technically, a part of the application container system. Facades are a second system built on top of the application container.
In addition to providing a convenient alias for accessing a service class, the facade implementation also forces the service object into a single-instance/singleton irrespective of how you've bound it into the container. This happens in the base facade class here
#File: vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) return $name;
if (isset(static::$resolvedInstance[$name]))
{
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
The base facade class keeps an instance cache in static::$resolvedInstance. The specifics of how Laravel gets here are a bit long for a StackExchange answer, but my Unraveling Laravel Facades article (part of a longer series) is a good place to start.
The problem here (again, based on the incomplete information provided) appears to be a misunderstanding of facades. The main takeaway is a facade always forces a service object to be a singleton.
Am having problems understanding where classes should be kept in CI. I am building an application that describes / markets mobile phones.
I would like for all of my functions (i.e. getphone, getdetails etc.) to reside in one class called Mobile - I understand that this file should be called Mobile.php and reside in the controllers folder.
Can I then have multiple functions inside Mobile.php? E.g.
public function getphone() {
xxx
xx
xx
}
public function getdetails() {
xxx
xx
xx
}
Or do I need to put each function in its own class?
I'd really appreciate looking at some sample code that works. I've been going through the documentation and google for a few hours, and tried all sorts of variations in the URL to find a test class, but without much luck! I've even messed around with the routes and .htaccess...
All I am trying to achieve is the following:
http:///model/HTC-Desire/ to be re-routed to a function that accepts HTC-Desire as a parameter (as I need it for a DB lookup). The default controller works fine, but can't get anything to work thereafter.
Any ideas?
Thanks
Actually it works like this:
Controllers and Models go to their perspective folders as you know it
If you want to create functions that are not methods of an object, you must create a helper file. More info here :
http://codeigniter.com/user_guide/general/helpers.html
Now if you want to create your own datatypes (classes that don't extend Models and Controllers), you add them to the library folder. So if let's say you want to create a class "Car" you create this file:
class Car{
function __construct(){}
}
and save it in the libraries folder as car.php
To create an instance of the Car class you must do the following:
$this->load->library('car');
$my_car = new Car();
More information on libraries here:
http://codeigniter.com/user_guide/general/creating_libraries.html
Yes, you can have as many functions in a controller class as you'd like. They are accessible via the url /class/function.
You can catch parameters in the class functions, though it's not advisable.
class Mobile extends CI_Controller{
public function getPhone($phoneModel=''){
echo $phoneModel;
//echo $this->input->post('phoneModel');
}
}
http://site.com/mobile/getPhone/HTC-Rad theoretically would echo out "HTC-Rad". HOWEVER, special characters are not welcome in URL's in CI by default, so in this example you may be met with a 'Disallowed URI characters" error instead. You'd be better off passing the phone model (or any other parameters) via $_POST to the controller.
Classes can exist both as Controllers and Models, as CodeIgniter implements the MVC pattern. I recommend reading more about that to understand how your classes/functions/etc. can best be organized.
Off the top of my head, Pyro CMS is an application built with CodeIgniter and the source code is freely available. I'm sure there are others.
I think it's best you handle it from one perspective, that is; create a utility class with all your functions in it.
The answer to the question of where to put/place the class file is the "libraries" folder.
This is clearly stated in the documentation. Place your class in the libraries folder.
When we use the term “Libraries” we are normally referring to the
classes that are located in the libraries directory and described in
the Class Reference of this user guide.
You can read more on creating and using libraries Creating Libraries — CodeIgniter 3.1.10 documentation
After placing the newly created class in the libraries folder, to use just simply load the library within your controller as shown below:
$this->load->library('yourphpclassname');
If you wish to receive several arguments within you constructor you have to modify it to receive an argument which would be an array and you loading/initialization would then be slightly different as shown below:
$params = array('type' => 'large', 'color' => 'red');
$this->load->library('yourphpclassname', $params);
Then, to access any of the functions within the class simply do that as shown below:
$this->yourphpclassname->some_method();
I hope this answers your question if you have further question do leave a comment and I would do well to respond to them.
When you are using code igniter you load a library or model like so
$this->load->library('mylibrary');
$this->load->model('mymodel');
So, in a real world example, lets say you have a controller called user.
So, to login a user you send them to http://example.com/user/login
Now the login function loads a form that submits to http://example.com/user/login_do
You do some simple checks, and then send it over to your model to do the database check for you.
So you call
$this->load->model('user');
if($this->user->validate($email, $pass)){...}
UH OH!
Fatal error: Cannot redeclare class
User in
/var/www/unity/src/application/models/User_Model.php
on line ...
So what happened? Well, Code igniter does not segregate the classes, so your model now conflicts with your controller,
sure you can use
$this->load->model('user_model', '', 'user_m');
if($this->user_m->validate($email, $pass)){...}
So, Onto my question.
Why does code igniter not segregate the classes,
e.g. so you would call
$this->load->model('user');
if($this->model->user->validate($email, $pass)){...}
Sure it's slightly longer, but hell it would make things heaps nicer to user.
is it possible to extend code igniter so it works in this way?
It's not exactly the solution you're asking for (or a great idea), but there's nothing stopping you from doing this:
class Users extends CI_Controller {
private $model;
private $m;
public function __construct()
{
parent::__construct();
$this->load->model('user_model');
$this->model->users = $this->user_model;
$this->m = $this->user_model;
}
function index()
{
// Here's that syntax you wanted
$this->model->users->get_many();
// Even shorter
$this->m->get_many();
}
}
You can really just assign anything to any property of the controller you want, as long as it's not the name of a loaded class or property (session, router, etc.). It can save you some typing if your model names are really long, but otherwise it's pointless and may conflict with things in the future.
Here's what I do if I'm not using *_model for model names:
Controller name: Users (plural)
Model name: User (singular)
No conflict, short syntax, sensible naming, it just doesn't work for some names like "news".
As I mentioned, it would be nice to see controller names using something like Controller_User or User_Controller to clear up the namespace issues a bit for the classes that we actually do have to call frequently, like models and libraries, but keep our urls as normal. I'm sure it can be done, something for a rainy day...
You missing the main point, PHP doesn't allow two classes with the same name, basically that's what Cannot redeclare class User says.