yii error active record query - database

i'm trying to use yii and i follow a tutorial to simple create a page that shoe fields of database's table.
i create index view
<?php
/* #var $this yii\web\View */
?>
<h1>articoli/index</h1>
<p>
pippo
<?php
foreach($posts as $post){?>
<h1><?php echo $post->autore; ?> </h1>
<p><?php echo $post->articolo; ?></p>
}
?>
</p>
in controllers i create ArticoliController
<?php
namespace app\controllers;
class ArticoliController extends \yii\web\Controller
{
public function actionIndex()
{
$posts=Articoli::model()->findall();
$data['posts']=$posts;
return $this->render('index',$data);
}
public function actionSaluta(){
$vsa['messaggio']='Alessio';
return $this->render('saluta',$vsa);
}
}
in model i create Articoli .php
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "articoli".
*
* #property integer $id
* #property string $autore
* #property string $articolo
*/
class Articoli extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'articoli';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['articolo'], 'required'],
[['autore'], 'string', 'max' => 55],
[['articolo'], 'string', 'max' => 255],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'autore' => 'Autore',
'articolo' => 'Articolo',
];
}
}
when i try it return
PHP Fatal Error – yii\base\ErrorException
Class 'app\controllers\Articoli' not found
i don't understand. I think that it must go to app\models\Articoli.php
I try different way
$posts=Articoli::->findall();
but don't work

Yii2 ActiveRecord don't have static function model(). To fetch all records from Articoli you have to use findAll() static method, or find()->all().
Change usage in controller to:
$posts = Articoli::findAll();
In your controller add use:
use \app\models\Articoli;
Or just change this line:
$posts=Articoli::model()->findall();
to this:
$posts = \app\models\Articoli::findAll();
And that's all! ;)

Related

Laravel 8.1 how to make seeder of user table

I am trying to seed the user table but I am facing some issues can someone guide me where I am missing.
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
DB::table('users')->insert([
'name' => Str::random(10),
'email' => Str::random(10).'#example.com',
'password' => Hash::make('password'),
]);
}
}
I think you are missing the below line
use Illuminate\Support\Str;
The complete code look like
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeders.
*
* #return void
*/
public function run()
{
DB::table('users')->insert([
'name' => Str::random(10),
'email' => Str::random(10).'#gmail.com',
'password' => Hash::make('password'),
]);
}
}
Try something like this using eloquent instead of the DB class with an existence check too:
<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class UsersTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
// Seed test user 1
$seededAdminEmail = 'admin#admin.com';
$user = User::where('email', '=', $seededAdminEmail)->first();
if ($user === null) {
$user = User::create([
'name' => 'Admin',
'email' => $seededAdminEmail,
'password' => Hash::make('password'),
]);
}
// Seed test user 2
$user = User::where('email', '=', 'user#user.com')->first();
if ($user === null) {
$user = User::create([
'name' => 'User',
'email' => 'user#user.com',
'password' => Hash::make('password'),
]);
}
}
}

CakePHP 4.1 User entity as authorization identity associated fields

I have just created a very minimal project in CakePHP 4.1, mostly mimicking the CMS tutorial, and want to implement a fairly straightforward piece of logic.
Using the Authorization module I want to allow a user A to be able to view a user B if 1) they are actually the same user (A = B) OR 2) if A is an admin.
There are two DB tables - users and user_types. users has a foreign key user_type_id to user_types.
This relationship is reflected in code as:
##### in UsersTable.php #####
class UsersTable extends Table {
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('users');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->belongsTo('UserTypes');
$this->addBehavior('Timestamp');
}
//...
}
##### in UserTypesTable.php #####
class UserTypesTable extends Table {
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('user_types');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->hasMany('Users');
}
//...
}
In UsersController.php I have:
public function view($id = null)
{
$user = $this->Users->get($id, [
'contain' => ['UserTypes'],
]);
$this->Authorization->authorize($user);
$this->set(compact('user'));
}
And in UserPolicy.php:
use App\Model\Entity\User;
class UserPolicy
{
public function canView(User $user, User $resource)
{
// TODO: allow view if $user and $resource are the same User or if $user is an admin
//
// My problem is that here $user->user_type is NULL
// while $resource->user_type is populated correctly
}
}
The code comment in the above excerpt shows where my problem is.
I do not know how to get $user to have its user_type field populated in order to check whether they're an admin.
As a part of my efforts, I have set the User class to be the authorization identity, following this article: https://book.cakephp.org/authorization/2/en/middleware.html#using-your-user-class-as-the-identity.
Code-wise this looks like:
##### relevant part of Application.php #####
$middlewareQueue
->add(new AuthenticationMiddleware($this))
->add(new AuthorizationMiddleware($this, [
'identityDecorator' => function(\Authorization\AuthorizationServiceInterface $auth, \Authentication\IdentityInterface $user) {
return $user->getOriginalData()->setAuthorization($auth);
}
]));
##### User.php #####
namespace App\Model\Entity;
use Authentication\PasswordHasher\DefaultPasswordHasher;
use Authorization\AuthorizationServiceInterface;
use Authorization\Policy\ResultInterface;
use Cake\ORM\Entity;
/**
* User Entity
*
* #property int $id
* #property string $email
* #property string $password
* #property string|null $name
* #property \App\Model\Entity\UserType $user_type
* #property \Cake\I18n\FrozenTime|null $created
* #property \Cake\I18n\FrozenTime|null $modified
* #property \Authorization\AuthorizationServiceInterface $authorization
*/
class User extends Entity implements \Authorization\IdentityInterface, \Authentication\IdentityInterface
{
protected $_accessible = [
'email' => true,
'password' => true,
'name' => true,
'created' => true,
'modified' => true,
];
/**
protected $_hidden = [
'password',
];
protected function _setPassword(string $password) : ?string
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher())->hash($password);
}
}
/**
* #inheritDoc
*/
public function can(string $action, $resource): bool
{
return $this->authorization->can($this, $action, $resource);
}
/**
* #inheritDoc
*/
public function canResult(string $action, $resource): ResultInterface
{
return $this->authorization->canResult($this, $action, $resource);
}
/**
* #inheritDoc
*/
public function applyScope(string $action, $resource)
{
return $this->authorization->applyScope($this, $action, $resource);
}
/**
* #inheritDoc
*/
public function getOriginalData()
{
return $this;
}
/**
* Setter to be used by the middleware.
* #param AuthorizationServiceInterface $service
* #return User
*/
public function setAuthorization(AuthorizationServiceInterface $service)
{
$this->authorization = $service;
return $this;
}
/**
* #inheritDoc
*/
public function getIdentifier()
{
return $this->id;
}
}
However, I have not been able to get the identity User in the UserPolicy.php file to have the user_type field populated.
Some under-the-hood magic seems to happen when I call $this->Authorization->authorize() from the controller where I explicitly pass the resource together with its user type (since I have constructed it with 'contain' => ['UserTypes'] BUT the identity user is populated automatically by the Authorization module.
Could someone please help me to find a way to bring associated tables data into the identity user of an authorization policy?
NOTE:
I have fudged the code to make it work like this:
##### in UserPolicy.php #####
use App\Model\Entity\User;
class UserPolicy
{
public function canView(User $user, User $resource)
{
$user = \Cake\Datasource\FactoryLocator::get('Table')->get('Users')->get($user->id, ['contain' => ['UserTypes']]);
// Now both $user->user_type and $resource->user_type are correctly populated
}
}
HOWEVER, this feels awfully "hacky" and not the way it's supposed to be, so my original question still stands.
The identity is being obtained by the resolver of the involved identifier. In case of the CMS tutorial that's the Password identifier which by default uses the ORM resolver.
The ORM resolver can be configured to use a custom finder in case you need to control the query for obtaining the user, that's where you should add the containment for your UserTypes association.
In your UsersTable add a finder like this:
public function findForAuthentication(\Cake\ORM\Query $query, array $options): \Cake\ORM\Query
{
return $query->contain('UserTypes');
}
and configure the identifier's resolver to use that finder like this:
$service->loadIdentifier('Authentication.Password', [
'resolver' => [
'className' => 'Authentication.Orm',
'finder' => 'forAuthentication',
],
'fields' => [
'username' => 'email',
'password' => 'password',
]
]);
You need to specify the resolver class name too when overriding the resolver option, as by default it is just a string, not an array that would merge with the new config!
See also
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Custom Finder Methods
Authentication Cookbook > Identifiers

Yii 2.0 - Trying to get property of non-object

I try to change the "ID Kategori"(Category ID) to "Nama Kategori" (Category Name), the Category ID is in product table and has a relation to category table.
for the gridView im using kartik-v gridView
i know the error is at return Html::a($model->kategori->deskripsi ,['kategori/view','id' => $model->Id]);, But i dont know whats the problem or how to fix it
please help me... >.<
[
'label' => 'Kategori',
'attribute' => 'IdKategori',
'format' => 'raw',
'vAlign' => 'middle',
'value' => function ($model, $key, $index) {
return Html::a($model->kategori->deskripsi ,['kategori/view','id' => $model->Id]);
},
],
and this is the model
<?php
namespace common\models;
use Yii;
/**
* This is the model class for table "produk".
*
* #property integer $Id
* #property integer $IdKategori
* #property string $nama_produk
* #property integer $harga_produk
* #property string $gambar
* #property string $deksripsi_produk
* #property string $detail_produk
*/
class Produk extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public $file;
public static function tableName()
{
return 'produk';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['IdKategori', 'nama_produk', 'harga_produk', 'gambar', 'deksripsi_produk', 'detail_produk'], 'required'],
[['IdKategori', 'harga_produk'], 'integer'],
[['file'], 'file'],
[['nama_produk', 'file', 'gambar', 'deksripsi_produk', 'detail_produk'], 'string', 'max' => 255],
[['IdKategori'], 'exist', 'skipOnError' => true, 'targetClass' => Kategori::className(), 'targetAttribute' => ['IdKategori' => 'Id']],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'Id' => 'ID',
'IdKategori' => 'Id Kategori',
'nama_produk' => 'Nama Produk',
'harga_produk' => 'Harga Produk',
'gambar' => 'Gambar',
'deksripsi_produk' => 'Deksripsi Produk',
'detail_produk' => 'Detail Produk',
];
}
public function getKategori()
{
return $this->hasOne(Kategori::className(), ['Id' => 'IdKategori']);
}
}
This is the kategori model
<?php
namespace common\models;
use Yii;
/**
* This is the model class for table "kategori".
*
* #property integer $Id
* #property integer $ParentId
* #property string $nama_kategori
* #property string $deskripsi
*/
class Kategori extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'kategori';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['ParentId', 'nama_kategori', 'deskripsi'], 'required'],
[['ParentId'], 'integer'],
[['nama_kategori', 'deskripsi'], 'string', 'max' => 255],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'Id' => 'ID',
'ParentId' => 'Parent ID',
'nama_kategori' => 'Nama Kategori',
'deskripsi' => 'Deskripsi',
];
}
}
I checked myself to make sure I can repeat your error and it seems to be the case.
In your database, table produkt has a column called IdKategori and at least 1 row contains either null or non-existing value for table kategori (non-existing value means that it has an ID that does not exist in kategori table).
You can solve that with (one example):
'value' => function ($model, $key, $index) {
if (empty($model->kategori->deskripsi)) {
return '';
} else {
return Html::a($model->kategori->deskripsi, ['kategori/view', 'id' => $model->Id]);
}
},

cakephp event listener not found

I'm using Cakephp 3.2 and proffer plugin to upload images.
By default the path of the image is as follows
/media/files/<tablename>/<primary_key>/<filename>
Each time a new row is inserted into same table a new folder is created by its primary key.
I want to upload all images of a table to the same directory. means path like
/media/files/<tablename>/<filename>
I'm using event listener as per given in proffer documentation.
This is my SellersTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\Event\Event;
class SellersTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$listener = new App\Event\UploadFileNameListener(); // line 23
$this->eventManager()->on($listener);
$this->table('sellers');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->addBehavior('Proffer.Proffer', [
'profile_picture' => [
'root' => Configure::read('ArgoSystems.media.upload') . DS . 'files',
'dir' => 'dir'
]
]);
}
/**
* Default validation rules.
*
* #param \Cake\Validation\Validator $validator Validator instance.
* #return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->requirePresence('first_name', 'create')
->notEmpty('first_name');
$validator
->requirePresence('last_name', 'create')
->notEmpty('last_name');
$validator
->email('email')
->requirePresence('email', 'create')
->notEmpty('email')
->add('email', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
$validator->provider('proffer', 'Proffer\Model\Validation\ProfferRules');
$validator
->add('profile_picture', 'proffer', [
'rule' => ['dimensions', [
'min' => ['w' => 100, 'h' => 500],
'max' => ['w' => 100, 'h' => 500],
]],
'message' => 'Image must be of 100 x 500 resolution',
'provider' => 'proffer'
])
->requirePresence('profile_picture', 'create')
->allowEmpty('profile_picture','update');
$validator
->requirePresence('password', 'create')
->notEmpty('password');
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->isUnique(['email']));
return $rules;
}
}
and created UploadFileNameListener.php in src/Event/
<?php
namespace App\Event;
use Cake\Event\Event;
use Cake\Event\EventListenerInterface;
use Cake\Utility\Inflector;
use Proffer\Lib\ProfferPath;
class UploadFileNameListener implements EventListenerInterface
{
public function implementedEvents()
{
return [
'Proffer.afterPath' => 'change',
];
}
/**
* Rename a file and change it's upload folder before it's processed
*
* #param Event $event The event class with a subject of the entity
* #param ProfferPath $path
* #return ProfferPath $path
*/
public function change(Event $event, ProfferPath $path)
{
// Detect and select the right file extension
switch ($event->subject()->get('image')['type']) {
default:
case "image/jpeg":
$ext = '.jpg';
break;
case "image/png":
$ext = '.png';
break;
case "image/gif":
$ext = '.gif';
break;
}
// Create a new filename using the id and the name of the entity
$newFilename = $event->subject()->get('id') . '_' . Inflector::slug($event->subject()->get('name')) . $ext;
// set seed
$path->setSeed('profile_picture');
// Change the filename in both the path to be saved, and in the entity data for saving to the db
$path->setFilename($newFilename);
$event->subject('image')['name'] = $newFilename;
// Must return the modified path instance, so that things are saved in the right place
return $path;
}
}
But this is giving Fatal error as
Error: Uncaught Error: Class 'App\Model\Table\App\Event\UploadFileNameListener' not found in
/var/www/html/projects/admin/src/Model/Table/SellersTable.php:23
From the error message, it's clear that it's trying to load the class with a namespace relative to the namespace of your current class. Try
$listener = new \App\Event\UploadFileNameListener();

Cakephp Call to undefined method Directory::find() after changing the classname

I'm using Cakephp 2.4.
I named one of my table folders (which was a logic name) but I just discover that was a reserved word in cake ... So I tried to change folders to directories (in model/controller/views) but i still get the error
Call to undefined method Directory::find()
My model is now
Directory.php
:
<?php
App::uses('AppModel', 'Model');
/**
* Directory Model
*
* #property Installation $Installation
*/
class Directory extends AppModel {
/**
* Display field
*
* #var string
*/
public $displayField = 'name';
public $useTable = 'directories';
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* belongsTo associations
*
* #var array
*/
public $belongsTo = array(
'Installation' => array(
'className' => 'Installation',
'foreignKey' => 'installation_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
I also change hasMany array in my Installation model
My controller
DirectoriesController.php
<?php
App::uses('AppController', 'Controller');
/**
* Directories Controller
*
* #property Directory $Directory
* #property PaginatorComponent $Paginator
*/
class DirectoriesController extends AppController {
/**
* Components
*
* #var array
*/
public $components = array('Paginator');
}
Can someone tell me where I may have missed something ?
Thank you for your help and sorry for my english.

Resources