I have setup an event that does some stuff once a user registers. Updating and inserting etc, but it won't work.
I get the error:
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_ERROR)
Class 'EventHandlers\Handlers\User' not found
I don't know why it won't work. But I haven't misspelled anything, because if I eg "return 'test';" in my event it works, but it won't update my userModel
In my Usercontroller:
$user = User::create([
some values..
]);
Event::fire('user.create', $user);
Now I subscribe to events in my app/start/global.php, I autoload the folder using PSR-4
Event::subscribe('EventHandlers\Handlers\UserAccountActions');
Event::subscribe('EventHandlers\Handlers\ProductActions');
Event::subscribe('EventHandlers\Handlers\CommentActions');
And in my event/listener file
<?php namespace EventHandlers\Handlers;
class UserAccountActions {
// Listeners
public function subscribe($events)
{
$events->listen('user.create', 'EventHandlers\Handlers\UserAccountActions#onCreate');
}
// happens when a user register
public function onCreate($user)
{
$user->api_key = User::createApiKey();
}
}
In your EventHandlers\Handlers\UserAccountActions you refer to User as it was in the same namespace. You need to add a backslash \ to access the User class in the global namespace:
// happens when a user register
public function onCreate($user)
{
$user->api_key = \User::createApiKey();
}
(Or specify the namespace if the User model is in one. e.g. \Models\User)
Alternatively you can also import the model with a use statement:
use User;
class UserAccountActions {
Related
I try to use the Entity of another Bundle in my Symfony Controller:
use Acme\TestBundle\Entity\Neighbour;
use AppBundle\Entity\Home;
class TestController extends Controller {
public function testAction(Home $home, Neighbour $neighbour) {
//
}
}
but this throws an 404 Error:
Acme\TestBundle\Entity\Neighbour object not found
this is different to a real not existing object like NeighbourX, there it throws an 500 error:
Acme\TestBundle\Entity\Neighbour does not exist
The object exists, and it should work, because this works:
use Acme\TestBundle\Entity\Neighbour;
use AppBundle\Entity\Home;
class TestController extends Controller {
public function testAction(Home $home) {
$thread = new ForumThread();
}
}
Ok I already found the answer myself. I had to specify the route variable:
/home/{id}/neighbour/{nid} #before
/home/{id}/neighbour/{neighbour} #after
But I don't fully understand it. Why doesn't {id} has to be {home}? Is {id} just the first parameter-id by default?
And why is the error message that misleading..
I'm creating an abstract class that will grab the contents of a view using Laravel's View class. But I'm getting the following error when trying to run a method from a class that extends it:
Illuminate \ Container \ BindingResolutionException
Target [Illuminate\View\Engines\EngineInterface] is not instantiable.
Here's my code:
PdfReport.php
use Illuminate\View\View as View;
abstract class PdfReport {
private $view;
function __construct(View $view)
{
$this->view = $view;
}
public function render($reportView, $report)
{
$this->view->make('report.pdf.' . $reportView, ['report' => $report])->render();
}
}
EslReport.php
<?php namespace Reports\PdfReports;
class EslPdfReport extends PdfReport {
public function renderReport($report)
{
return $this->render('esl', $report);
}
}
Then I'm running my code in routes.php for testing purposes as follows:
use Reports\PdfReports\EslPdfReport;
Route::get('pdftest', array(
'as' => 'pdftest',
function(){
$eslReport = App::make('Reports\PdfReports\EslPdfReport');
$eslReport->renderReport(EslReport::find(1));
}
));
I'm not quite understanding if I'm doing something wrong with the dependency injection for the view in the abstract class, it's all pretty new concepts to me, so any help would be most appreciated.
Also I asked this question on laracasts forum if it helps: https://laracasts.com/discuss/channels/general-discussion/confusion-about-constructors-in-abstract-classes
Instead of Illuminate\View\View you need to inject Illuminate\View\Factory:
use Illuminate\View\Factory as View;
Here's a reference of facade classes and there actual underlying class you need to use when working with DI
I have a model like this:
class Event extends Eloquent
{
protected $softDelete = true;
public function scopeSearchEvents($search_criteria)
{
return Event::whereIn('title',$search_criteria)
->orWhereIn('description',$search_criteria)
->whereApproved('1')
->orderBy('event_date','desc')
->get();
}
}
And im calling it from the controller like this:
$data = Event::search($search_criteria);
But it gives this error:
Symfony \ Component \ Debug \ Exception \ FatalErrorException
Call to undefined method Illuminate\Events\Dispatcher::search()
What is the best way of calling a custom model method from your controller?
Make changes to your method as given below:
public function scopeSearchEvents($query, $search_criteria)
{
return $query->whereIn('title', $search_criteria)
->orWhereIn('description', $search_criteria)
->whereApproved('1')
->orderBy('event_date','desc');
}
Then call it like searchEvents not search:
// Don't use Event as your model name
$data = YourModel::searchEvents($search_criteria)->get();
Also make sure that, you want to use whereIn instead of where('title', 'LIKE', "% $search_criteria") and so.
Update:
You should change the model name from Event to anything else because Laravel has it's core Event class, actually a Facade which is mapped to 'Illuminate\Support\Facades\Event'.
Have a look at the app.php:
'aliases' => array(
...
'Event'=> 'Illuminate\Support\Facades\Event',
...
);
"Event" is defined as an alias. That's why your Event calls "Illuminate\Support\Facades\Event".
Now if you want to use your event model without typing the namespace to call methods create an alias like:
'MyEvent' => 'App\Models\Event',
and then:
MyEvent::create();
In normal way i can able to define an object through out the application by defining a service factory in configuration file global.php
i can get the object in controller by just calling $this->getServiceLocator()->get('mycollection')
My code as follows:
In global.php
service_manager' => array(
'factories' => array(
'mycollection'=> function($sm){
$collectionAdapter = new Collection();
$collectionAdapter->addItem("testvalue",'test');
return $collectionAdapter;
}
By adding in global file i can able to retrieve
//`var_dump($this->getServiceLocator()->get('mycollection')->getItem("test"));// will return testvalue`
through out the application
But my issue is that i dont know how to accomplish set values to the service from a controller
My requirement is that i need to set the service in one controller and retrieve in another module
i tried the following code in my IndexController album module
$this->getServiceLocator()->get('mycollection')->addItem('testvalue28','test8');
and in another module student IndexController called
//var_dump($this->getServiceLocator()->get('mycollection')->getItem("test8"));//
How can i accomplish the same which i set in global.php in a controller . or more clearly i need to store the collection values to the entire application at one instance in all modules
Edited
1)The function addItem will be set only based on controller action
2)Is there any thing similar to ZEND_REGISTERY where i can set a value form a particular request and retrieve in another action
//An application controller is define where i need to set different key value pair
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class IndexController extends AbstractActionController
{
public function authenticateAction()
{
//----other code---------
var_dump($this->getServiceLocator()->get('mycollection')->addItem('userauthenticationobj','userkey'));
//$redirect=module=user controller action =index
return $this->redirect()->toRoute($redirect);
}
}
In user module index action i need to get the key value pair which is set inside application module in index action. i know this can be done using a session or db or cookies but i want to implement this using a singleton instance through out the application. i don't know to define the correct term in oops so defining the situation
//User controller
namespace User\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class IndexController extends AbstractActionController
{
public function authenticateAction()
{
//----other code---------
var_dump($this->getServiceLocator()->get('mycollection')->addItem('userkey'));
//$redirect=module=user controller action =index
return $this->redirect()->toRoute($redirect);
}
}
//IN GLOBAL.PHP i defined
return array(
'service_manager' => array(
'factories' => array(
'mycollection'=> function($sm){
$collectionAdapter = new Collection();
$collectionAdapter->addItem("testvalue",'test');
return $collectionAdapter;
}
),
),
);
//user defined collection reference: http://www.sitepoint.com/collection-classes-in-php/
namespace Application\Adapter;
class Collection
{
private $items = array();
public function addItem($obj, $key = null)
{
if ($key == null)
{
$this->items[] = $obj;
}
else {
if (isset($this->items[$key]))
{
throw new \Exception("Key $key already in use.");
}
else
{
$this->items[$key] = $obj;
}
}
}
public function getItem($key)
{
if (isset($this->items[$key]))
{
return $this->items[$key];
}
else
{
throw new \Exception("Invalid key $key.");
}
}
}
If you are in the same request (this is, the user is not following links, or the page is not being refreshed) the service manager will keep the Collection alive and what you are trying should work.
But if you are redirecting the user to another controller/action, or the user has followed a link, submited a form, or whatever that causes a new page to be loaded, all the values created in the previous page wont exists anymore. If you need to persist them, you should use sessions, cookies, database, etc.
If the values are not set during the action, i.e you dont need a controller to be loaded, but you need all the controllers to be able to add values to the collection on the application bootstrap, no matter what controller is actually loaded, you can add some code to every module, in Module.php onbootstrap function. for instance, in every module's Module.pho, you do:
public function onBootstrap(MvcEvent $e) {
$sm = $e->getApplication ()->getServiceManager ();
$collection = $sm->get('mycollection');
$collection->addItem('testvalue_N','test_N');
}
and then, in every controller/action that is executed, you will have the collection with all the items added by all the modules
I want to extend/overwrite the method logAttempt in class Confide (Confide on GitHub) in order to execute some extra code whenever someone logs in successfully. This would be cleaner than copying the same code to all controllers where logAttempt is called.
I read through the Laravel documentation and several answers here on stackoverflow, but I just can't get it working.
I created a new folder app/extensions with a file named Confide.php:
<?php
namespace Extensions;
class Confide extends \Zizaco\Confide\Confide {
public function __construct(ConfideRepository $repo) {
die('no way!');
$this->repo = $repo;
$this->app = app();
}
public function logAttempt($credentials, $confirmed_only = false, $identity_columns = array()) {
die('yeah man!');
}
}
I added the directory to my app/start/global.php:
ClassLoader::addDirectories(array(
// ...
app_path().'/extensions',
));
I also added it to composer.json and ran composer dump-autoload:
"autoload": {
"classmap": [
...,
"app/extensions"
]
},
My own Confide class seems not to be loaded at all, because Confide works as normal – without ever die()-ing.
And if I use \Extensions\Confide::logAttempt($input, true); in my controller including the namespace, I get this ErrorException:
Non-static method Extensions\Confide::logAttempt() should not be called statically, assuming $this from incompatible context
Do I really need my own ConfideServiceProvider class as well? I tried that, too, but I'm not sure at all what to put in there to make Confide use my extended class.
Is there no simple way to extend a tiny bit of a class? There must be, I'm just missing something here.
If you are looking to execute some code when a user logs in, you should just listen for that event. In this case, I believe Confide uses the Auth class to login, so you should be able to listen for that event.
Event::listen('auth.login', function($user)
{
$user->last_login = new DateTime;
$user->save();
});
I find this much easier and cleaner than worrying about extending classes.
EDIT: Made a mistake
I think you need to call the method like this:
\Extensions\Confide->logAttempt($input, true);
because you are using:
\Extensions\Confide::logAttempt($input, true);
Which is how you call static methods.
I think I finally figured it out.
I had to extend ConfideServiceProvider as well like so:
<?php
namespace Extensions;
class ConfideServiceProvider extends \Zizaco\Confide\ConfideServiceProvider {
/**
* Bootstrap the service provider.
*
* #return void
*/
public function boot() {
$this->package('extensions/confide');
}
/**
* Register the application bindings.
*
* #return void
*/
protected function registerConfide() {
$this->app->bind('confide', function($app) {
return new Confide($app->make('confide.repository'));
});
}
}
The code above goes into app/extensions/ConfideServiceProvider.php. Note: In boot() I replaced "zizaco" with "extensions" and in registerConfide() I made no changes at all, but if this method is not present in the extended class, the original class will be used. I've got no idea why.
Then in app/config/app.php I replaced Zizaco\Confide\ConfideServiceProvider with Extensions\ConfideServiceProvider.
My own extended Confide class looks like this now:
<?php
namespace Extensions;
class Confide extends \Zizaco\Confide\Confide {
public function logAttempt($credentials, $confirmed_only = false, $identity_columns = array()) {
$result = parent::logAttempt($credentials, $confirmed_only, $identity_columns);
if ($result) {
// Login successful. Do some additional stuff.
\Log::info('User ' . \Auth::user()->username . ' logged in.');
}
return $result;
}
}
Note: If you want to use any other standard Laravel class like Log, Session etc., prefix it with one backslash as shown in the example above, or add a use operator for each class you use (e.g. use \Log;).