How to get this code work to store in Laravel. No errors and no storage - database

I can't store name and IP address to DB. I created a table 'info' with appropriate fields by running php artisan migrate.
A schema
Schema::create('info', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('ip');
$table->timestamp('created_at')->nullable();
});
A model for Info
class Info extends Model
{
protected $fillable = ['ip', 'name'];
}
Maybe the problem is in my HomeController where I get those variables?
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Info;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Request;
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function store(Request $request) {
Info::create(['info' => $request->input('info')]);
}
public function index()
{
if (Auth::check())
{
$name = Auth::user()->name;
$ip = Request::ip();
\App\Events\eventIp::dispatch($ip,$name);
return view('home');
}
}
}
My routes in web.php
Route::post('/home','HomeController#store');
Route::get('/home', 'HomeController#index')->name('home');
});
But it doesn't work. Gives no errors and no records in DB.
Something make me think that it have to do with my index function. I got info in function index and maybe function store doesn't have a clue what I mean.

A controller action is basically a method that usually gets executed when you open an url (as you connect them to routes).
In your example you have connected two routes to their respective actions:
Route::post('/home','HomeController#store');
Route::get('/home', 'HomeController#index')->name('home');
Now, when you log in succesfully, imagine that you end up in the page with url http://localhost:8000/home in your web browser.
The key difference is the method which you use to call your route (you can get an overview of the differences here), in your case you are using GET method.
The resulting action executed it the one associated to /home route with the GET method, that is the HomeController#index action (or method).
The store method, although is in the same HomeController class, doesn't get triggered unless you execute the /home route, but with the POST method.
You can confirm that if you put a debug message in each of the methods like this:
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function store(Request $request)
{
echo 'I will not be executed';
}
public function index()
{
echo 'I have been executed';
}
}
If you want to simply save a info record when you visit the /home route with the GET method, you can put the save in the index method itself and get rid of the store method:
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
// You can omit Auth::check() because you are using the auth middleware
// that exactly does this job.
Info::create([
'name' => Auth::user()->name,
'ip' => Request::ip(),
]);
return view('home');
}
}
Keep in mind that doing in this way you will get a new database record for each page view you make to that route (if you keep refreshing the page, you should see new records being added to database).
Update
When you use Eloquent Models, laravel will look for a table named after the pluralized model name (Info model will try to use infos table).
However you created a table named info. To solve that you can either rename the table and rerun the migration with php artisan migrate:refresh (it will delete all the existing data in the database you are using for your laravel app)
Or specify the table name to use for that laravel model:
class Info extends Model
{
protected $table = 'info';
protected $fillable = ['ip', 'name'];
}

How are you calling the functions? There is a couple of things wrong with your code, but you're saying there are no errors at all.
Firstly, your Info::create call does not need the ['info' => $request->input('info')] info. This is because your Info model has no database property called info, but normally you would get an obvious error with the approach, which is why I expect you are also calling the store method incorrectly.
Call the create method like so:
$infoModel = Info::create(['name' => $request->input('name'), 'ip' => $request->input['ip']]);
or, if you can guarantee your $request only contains the needed fields (properly validated), you can just do
$infoModel = Info::create($request->all());
Add a little more info to the question on how you are calling store and we can probably solve the rest of your problem.

Within your store function inside HomeController , use
Info::create([
'name' => Auth::user()->name,
'ip' => Request::ip(),
]);
and make sure Info model is imported.
Also make sure your route has the call to store function while POSTing data .

Related

Auth.afterIdentify is not firing

I need to change something in the user session after it was started. This is temporary, so using an event such as Auth.afterIdentify is what I'm looking for.
What I tried
I have largely referred to this answer on how to even approach this.
I have tried using an anonymous function callback as well as a controller callback method
Following the Auth.afterIdentify documentation I have added implementedEvents
Made sure implementedEvents has a + parent::implementedEvents(), otherwise the controller kept showing me the home page
What I have
Here's my current src/Controller/AppController.php:
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller implements \Cake\Event\EventListenerInterface
{
public function initialize()
{
parent::initialize();
// …
$this->loadComponent('Authentication.Authentication');
// Trying with an anonymous function
\Cake\Event\EventManager::instance()->on('Auth.afterIdentify', function ($event) {
Log::write( // noticed when posting this question, should have thrown an error
'info',
'Testing: ' . $event->getSubject()->id
);
debug($event);exit;
});
// Trying a controller callback
\Cake\Event\EventManager::instance()->on('Auth.afterIdentify', [$this, 'afterIdentify']);
}
public function beforeFilter(\Cake\Event\Event $event)
{
parent::beforeFilter($event);
$this->set('myAuth', $this->Authentication->getResult());
$this->set('myUser', $this->Authentication->getIdentity());
}
public function afterIdentify(CakeEvent $cakeEvent, $data, $auth) {
debug([
'$cakeEvent' => $cakeEvent,
'$data' => $data,
'$auth' => $auth,
]);exit;
}
public function implementedEvents()
{
return [
'Auth.afterIdentify' => 'afterIdentify',
] + parent::implementedEvents();
}
}
What doesn't work
It seems neither of the above event listeners is being called. No CakePHP logs are being updated (not even with errors), although they normally work.
What I expected to happen
Calling Log::write without declaring where it comes from should have thrown (and logged) an error
The debug() information was not displayed
Removing the public function afterIdentify method should have caused an error; it didn't – meaning the controller isn't even looking for it
You are mixing up the old auth component and the new authentication plugin, the Auth.afterIdentify event belongs to the former.
The authentication plugin's authentication component has a Authentication.afterIdentify event, but this only applies to authenticators that are stateful and do not implement automatic persisting. So out of the box this only applies to the Form authenticator, and the event is being triggered once on the request where the user was authenticated via the form, on subsequent requests where they are authenticated via for example the Session authenticator, the event is not being triggered.
public function initialize()
{
parent::initialize();
// ...
$this->loadComponent('Authentication.Authentication');
$this->Authentication->getEventManager()->on(
'Authentication.afterIdentify',
function (
\Cake\Event\EventInterface $event,
\Authentication\Authenticator\AuthenticatorInterface $provider,
\Authentication\IdentityInterface $identity,
\Authentication\AuthenticationServiceInterface $service
) {
// ...
$identity['foo'] = 'bar';
$this->Authentication->setIdentity($identity);
}
);
}

Error: Call to a member function newEntity() on boolean

I am new on cakephp. I have done all the required steps but still having trouble in saving data in database with cakephp
code of adduser function from Articlecontroller.php:
public function adduser()
{
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->getData());
// Hardcoding the user_id is temporary, and will be removed later
// when we build authentication out.
$user->user_id = 1;
if ($this->Users->save($user)) {
$this->Flash->success(__('Your article has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your article.'));
}
$this->set('article', $user);
}
code of UserTable model:
<?php
// src/Model/Table/ArticlesTable.php
namespace App\Model\Table;
use Cake\ORM\Table;
class UsersTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
}
}
Data Base Table onto my locahost:
I think you forgot to load User model in controller. It should be fixed adding this line in function adduser() before first line. It should look like this.
public function adduser()
{
$this->loadModel('Users');
$user = $this->Users->newEntity();
...
Cakephp documentation.
https://book.cakephp.org/3.0/en/controllers.html#loading-additional-models
Well, you need to have a CakePHP application that is using the plugin. You need to add $this->loadComponent('Auth'); to your AppControllers initialize() method and configure it properly.
I highly recommend you to do the complete blog tutorial of the official CakePHP documentation or you won't have much fun with any plugin or anything else in the framework. It covers setting up Auth as well.
As other have started, when not in the controller related to the table you're accessing, you need to load the model and its related entities.
The current way of retrieving a table is through the table registry, as shown below:
use Cake\ORM\TableRegistry;
// Now $articles is an instance of our ArticlesTable class. This is how CakePHP 4 prefers it.
$articles = TableRegistry::getTableLocator()->get('Articles');
// Prior to 3.6.0
$articles = TableRegistry::get('Articles');
So for your public method, it should look like this:
public function adduser()
{
$usersTable = TableRegistry::getTableLocator()->get('Users');
$user = $usersTable->newEntity();
if ($this->request->is('post')) {
...code for handling post...
}
}
The CakePHP 3.x (and beyond) documentation regarding ORM outlines this well. While $this->loadModel('Articles') work, a quick search through the docs shows it is not frequently referred to neither in ORM section nor in examples.

Error: Cannot be accessed directly CakePHP

Element file I am calling:
$brand = $this->requestAction('brands/buyer_getnames/');
Action file I am calling:
public function buyer_getnames(){
$newid=$this->Auth->User('brand_id');
$name=$this->Brand->find('first',array('conditions'=>array('Brand.id'=>$newid),'recursive'=>-1));
return $name['Brand']['name'];
}
Getting error below..!!
Private Method in BrandsController
Error: BrandsController::buyer_getnames() cannot be accessed directly.
Please help
Request action respects normal url routing rules
If you're using prefix routing then you can't access function prefix_foo() via a url of the form /controller/prefix_foo - it needs to be the corresponding prefix url: /prefix/controller/foo.
As such your request action call should be:
$brand = $this->requestAction('/prefix/brands/getnames/');
Note that if the only thing that method does is call a model method, you're better off simply doing:
$model = ClassRegistry::init('Brand');
$brand = $model->someMethod();
You can allow unauthorized access to action if your action is requested with requestAction method.
For example:
public function beforeFilter() {
parent::beforeFilter();
if ($this->request->is('requested') && $this->request->params['action'] == 'index') {
$this->Auth->allow(array('index'));
}
}
This may also work (haven't tested):
public function index() {
if ($this->request->is('requested')) {
$this->Auth->allow(array('index'));
}
}
let me know if i can help you more.

AppModel aftersave, get controller function name

I'm trying to log every write operation so I'm using the afterSave and afterDelete callbacks in AppModel. Basically I need to log(for the moment): the model , the controller function, the loggedin user data and the remote ip
It seems that I was able to get all of them but I don't know how to get the controller function name.
This is the aftersave function I have now:
public function afterSave($created) {
App::uses('Folder', 'Utility');
$month = date("y-m");
if(!is_dir('../tmp/logs/'.$month)) {
$dir = new Folder('../tmp/logs/'.$month, true);
}
App::uses('CakeSession', 'Model/Datasource');
$user_id = CakeSession::read('Auth.User.username');
if($created) {
$id = 'New';
} else {
$id = $this->data[$this->alias]['id'];
}
$str = 'WRITE Action. Model: '.$this->alias.'. Controller: functon_name. ID:'.$id.'. Username: '.$user_id.'. Client IP: '.$this->getIP();
CakeLog::write($month.'/'.date("d-m-y"), $str);
}
Thanks
You're doing this on the model, which has no knowledge of the controller (and really shouldn't). I'd suggest copying the CakeRequest object to the model so you have that information. Here's one way:
//controller
function beforeFilter() {
$this->{$this->modelClass}->request = $this->request;
}
Then you can access the request object from the model. Use $this->request['params']['action'] to get the current dispatched action.
It's worth suggesting that you might want to move this to the read() method on a custom datasource, as afterSave() can possibly be skipped and therefore not logged.

CakePHP 2.1 HTTP cache

I'm trying to speed up my site by taking advantage of the new HTTP cache features in CakePHP 2.1:
class ArticlesController extends AppController {
public function view($id) {
$article = $this->Article->find(
'first',
array('conditions' => array('Article.id' => $id))
);
$this->response->modified($article['Article']['modified']);
$this->set(compact('article'));
}
}
Caching works fine, but does not distinguish between different users (i.e. if a user logs in and visits a page that was already cached, the previously cached page is displayed, and user-specific content is not shown). I'd like one of the following to happen:
Cache discriminates between different users and stores a separate cache for each user
Caching is disabled if a user is logged in (the user login is only used for admin purposes)
I've tried adding
if (AuthComponent::user('id')) {
$this->disableCache();
}
But this doesn't seem to solve the problem
Does anyone know how to get this to work, or am I doing something fundamentally wrong?
You could try the etag caching method and generate a hash based on the article id and user id.
See http://book.cakephp.org/2.0/en/controllers/request-response.html#the-etag-header
The Etag header (called entity tag) is string that uniquely identifies the requested resource. It is very much like the checksum of a file, caching will compare checksums to tell whether they match or not.
To actually get advantage of using this header you have to either call manually CakeResponse::checkNotModified() method or have the RequestHandlerComponent included in your controller:
<?php
public function index() {
$articles = $this->Article->find('all');
$this->response->etag($this->Article->generateHash($articles));
if ($this->response->checkNotModified($this->request)) {
return $this->response;
}
...
}
I thought I'd post the solution(s) I eventually used, in case it helps anyone.
To disable caching completely for logged in users:
class ArticlesController extends AppController {
public function view($id) {
$article = $this->Article->find(
'first',
array('conditions' => array('Article.id' => $id))
);
if (!AuthComponent::user('id')) {
$this->response->etag($this->Article->generateHash($article));
}
$this->set(compact('article'));
}
}
To have a separate cache for each user (and for the case when no-one is logged in):
class Article extends AppModel {
public function generateHash($article) {
if (AuthComponent::user('id')) {
return md5(AuthComponent::user('id') . '-' . $article['Article']['modified']);
} else {
return md5($article['Article']['modified']);
}
}
}
class ArticlesController extends AppController {
public function view($id) {
$article = $this->Article->find(
'first',
array('conditions' => array('Article.id' => $id))
);
$this->response->etag($this->Article->generateHash($article));
$this->set(compact('article'));
}
}

Resources