In the documentation exactly says that associated data can be saved like:
use App\Model\Entity\Article;
use App\Model\Entity\User;
$article = new Article(['title' => 'First post']);
$article->user = new User(['id' => 1, 'username' => 'mark']);
$articles = TableRegistry::get('Articles');
$articles->save($article);
I tried this in my code but I get error:
Fatal Error
Error: Class 'App\Controller\TableRegistry' not found
File /Users/mtkocak/Sites/gscrm/src/Controller/BusinessesController.php
Line: 62
Here is my controller code. I am doubt that above code is valid for entity models.
public function add() {
$business = $this->Businesses->newEntity($this->request->data);
$record = new Record($this->request->data['Records']);
$address = new Address($this->request->data['Addresses']);
$telephone = new Telephone($this->request->data['Telephones']);
$email = new Email($this->request->data['Emails']);
$record->business = $business;
$record->address = $address;
$record->email = $email;
if ($this->request->is('post')) {
var_dump($this->request->data['Records']);
$records = TableRegistry::get('Records');
$records->save($record);
// if ($this->Businesses->save($business)) {
// $this->Flash->success('The business has been saved.');
// return $this->redirect(['action' => 'index']);
// } else {
// $this->Flash->error('The business could not be saved. Please, try again.');
// }
}
$telephonetypes = $this->Businesses->Records->Telephones->Telephonetypes->find('list');
$records = $this->Businesses->Records->find('list');
$businesstypes = $this->Businesses->Businesstypes->find('list');
$this->set(compact('telephonetypes','business', 'records', 'businesstypes'));
}
Here is my sql dump of table:
CREATE TABLE IF NOT EXISTS `businesses` (
`id` int(10) unsigned NOT NULL,
`record_id` int(10) unsigned DEFAULT NULL,
`businesstype_id` int(10) unsigned DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci AUTO_INCREMENT=1 ;
ALTER TABLE `businesses`
ADD PRIMARY KEY (`id`), ADD KEY `FK_businesses_records` (`record_id`), ADD KEY `FK_businesses_businesstypes` (`businesstype_id`);
Any help is appreciated.
You are missing a use statement. All these examples in the book take for granted that you've started reading the tables section from the beginning and make use of:
http://book.cakephp.org/3.0/en/orm/table-objects.html#getting-instances-of-a-table-class
use Cake\ORM\TableRegistry;
ps. you don't have to build the entities manually when following the naming conventions
http://book.cakephp.org/3.0/en/orm/table-objects.html#converting-request-data-into-entities
http://book.cakephp.org/3.0/en/views/helpers/form.html#field-naming-conventions
http://book.cakephp.org/3.0/en/orm/table-objects.html#avoiding-property-mass-assignment-attacks
Related
I am working with the below code, which worked fine with typeorm 0.2.x. I am trying to upgrade my packages to 0.3.6. It could be that the problem is somehow Mac-specific. Yet, I am not sure.
The script is below:
import { MigrationInterface, QueryRunner } from 'typeorm';
export class CleanSlate1654889719399 implements MigrationInterface {
name = 'CleanSlate1654889719399';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query('IF EXISTS DROP TABLE "onetime_viewer_token" CASCADE');
...
await queryRunner.query(`CREATE TABLE IF NOT EXISTS "client_society_user" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "email" text NOT NULL, "tokenVersion" integer NOT NULL DEFAULT '0', "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), "role" "public"."client_society_user_role_enum" NOT NULL, "isInternalAdmin" boolean NOT NULL DEFAULT false, "clientId" uuid, CONSTRAINT "PK_599c2dd9d3dc21c54f7df5d9c7e" PRIMARY KEY ("id"))`);
...
await queryRunner.query(`ALTER TABLE "client_user" ADD CONSTRAINT "FK_eb3e491fab0ea63cd9f9ffba47d" FOREIGN KEY ("clientId") REFERENCES "client"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "discord_role" DROP CONSTRAINT "FK_cc3204010e82bba2a8cdafb30fc"`);
await queryRunner.query(`IF EXISTS DROP TABLE "onetime_transfer_token"`);
...
await queryRunner.query(`IF EXISTS DROP TABLE "temp_token"`);
}
}
When I am trying to run this migration with typeorm 0.3.x, it results in an error: error: syntax error at or near "IF".
Is it still possible to use QueryRunner with raw SQL? MigrationInterface only supports QueryRunner...
Please advise.
The below works fine [on both Mac and Linux] with typeorm 0.3.6:
await queryRunner.manager.query(...)
Given the following example for an Entity-Definition, there is a foreign key defined. As a developer and database engineer i would expect that the command dal:create:schema would also create the expected foreign keys. But this is not the case.
return new FieldCollection([
(new IdField('id', 'id'))->addFlags(new PrimaryKey(), new Required()),
(new LongTextField('comment', 'name'))->addFlags(new Required()),
(new FkField('order_id', 'orderId', OrderDefinition::class))->addFlags(new Required()),
new OneToOneAssociationField('order', 'order_id', 'id', OrderDefinition::class, false),
new CreatedAtField(),
new UpdatedAtField()
]);
Instead this is the result:
CREATE TABLE `order_refund` (
`id` BINARY(16) NOT NULL,
`comment` LONGTEXT NOT NULL,
`order_id` BINARY(16) NOT NULL,
`created_at` DATETIME(3) NOT NULL,
`updated_at` DATETIME(3) NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
However, it seems like that ManyToOneAssociations will add foreign keys. Is there something missing in the entity definition?
The command you mentioned is using the SchemaGenerator which has a method to generate Foreign keys:
\Shopware\Core\Framework\DataAbstractionLayer\SchemaGenerator::generateForeignKeys
Looking at this method it seems to work only fields of the type ManyToOneAssociationField
private function generateForeignKeys(EntityDefinition $definition): string
{
$fields = $definition->getFields()->filter(
function (Field $field) {
if (!$field instanceof ManyToOneAssociationField) {
return false;
}
return true;
}
);
I also think it is a shortcoming of this function that it does not generate foreign keys for fields of the type OneToOneAssociationField. Maybe you can try to adjust this filtering and see if it works and make a pull request on GitHub for the benefit of yourself and other developers?
Why is ON DELETE SET NULL failing when deleting a row via the application code, but it behaves correctly when manually executing an SQL statement?
I have a todo table and a category table. The todo table has a category_id foreign key that references id in the category table, and it was created with the "ON DELETE SET NULL" action.
create table `category` (
`id` integer not null primary key autoincrement,
`name` varchar(255) not null
);
create table `todo` (
`id` integer not null primary key autoincrement,
`title` varchar(255) not null,
`complete` boolean not null default '0',
`category_id` integer,
foreign key(`category_id`) references `category`(`id`) on delete SET NULL on update CASCADE
);
I also have an endpoint in my application that allows users to delete a category.
categoryRouter.delete('/:id', async (req, res) => {
const { id } = req.params
await req.context.models.Category.delete(id)
return res.status(204).json()
})
This route successfully deletes categories, but the problem is that related todo items are not getting their category_id property set to null, so they end up with a category id that no longer exists. Strangely though, if I open up my database GUI and manually execute the query to delete a category... DELETE FROM category WHERE id=1... the "ON DELETE SET NULL" hook is successfully firing. Any todo item that had category_id=1 is now set to null.
Full application source can be found here.
Figured it out, thanks to MikeT.
So apparently SQLite by default has foreign key support turned off. WTF!
To enable FKs, I had to change my code from this...
const knex = Knex(knexConfig.development)
Model.knex(knex)
to this...
const knex = Knex(knexConfig.development)
knex.client.pool.on('createSuccess', (eventId, resource) => {
resource.run('PRAGMA foreign_keys = ON', () => {})
})
Model.knex(knex)
Alternatively, I could have done this inside of the knexfile.js...
module.exports = {
development: {
client: 'sqlite3',
connection: {
filename: './db.sqlite3'
},
pool: {
afterCreate: (conn, cb) => {
conn.run('PRAGMA foreign_keys = ON', cb)
}
}
},
staging: {},
production: {}
}
FYI and other people who stumbled across a similar problem, you need PRAGMA foreign_keys = ON not only for the child table but also for the parent table.
When I set PRAGMA foreign_keys = ON only for a program which handles the child table, ON UPDATE CASCADE was enabled but ON DELETE SET NULL was still disabled. At last I found out that I forgot PRAGMA foreign_keys = ON for another program which handles the parent table.
I tried to install yii extension for one of my application. I am getting error of "Error 403 You are not authorized to perform this action." however from what i see in the database, the tables are created "authassignment","authitem","authitemchild","rights".
And under "authassignment" i have data
Admin 1 NULL N;
where 1 is my userid. This is correct as for my "user" table i have one account. The structure is
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int(10) AUTO_INCREMENT NOT NULL,
`login_id` varchar(255) NOT NULL,
`login_name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`level` int(3) NOT NULL DEFAULT '1',
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
i have then modified "config/main.php" to reflect the changes
'rights'=>array(
'install'=>false,
'superuserName'=>'Admin',
'userIdColumn'=>'user_id',
'userNameColumn'=>'login_id',
),
After numerous research, i think above steps are correct. However when i try to access /rights after installation. i face the problem again:
**Error 403 You are not authorized to perform this action**.
This is weird. I checked with installation document, there is nowhere mentioning this problem. So i guess that maybe because the way of login is wrong??
public function authenticate()
{
$array=$this->auth_array;
$criteria=new CDbCriteria;
$criteria->compare('email',$array['email']);
$u=User::model()->findAll($criteria);
if(count($u)==0)
{
$user = new User;
$user->email = $array['email'];
$user->login_name=$array['name'];
$user->login_id=$array['login_id'];
if($user->save()){
$this->_id=$user->user_id;
}
}else{
$this->_id=$u[0]->user_id;
}
$this->setState('user_id', $this->_id);
$this->setState('display_name',$array['display_name']);
$this->setState('name',$array['name']);
$this->setState('email',$array['email']);
$user=User::model()->findByAttributes(array('user_id'=>$this->_id));
if(count($user)>0)
{
if($user->level==1)
{
$this->setState('role', 'user');
}
else if($user->level==0)
{
$this->setState('role','admin');
}
$this->errorCode=self::ERROR_NONE;
}else{
$this->errorCode=self::ERROR_USERNAME_INVALID;
}
return !$this->errorCode;
}
Please help.
You should verify that id from authassignment table is the same as the id from the user table. It should be 1 in both cases.
Also verify that once you log in, you are indeed the superuser. You can check that with isSuperuser method. If you are not the super user you can set yourself to superuser via setSuperuser(bool) method.
I am a new at Zendframework 2. I am trying to join two tables and display the result.
The two tables are.
Works and Artist . The tables are joined based on artist_id.
STEP 1> Created 2 class(Works , Artist) in Model
STEP 2> In WorksTable I have the following code
class WorksTable extends AbstractTableGateway
{
protected $table ='works';
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new HydratingResultSet(
new ArraySerializableHydrator(),
new Works()
);
$this->resultSetPrototype->buffer();
$this->initialize();
}
public function fetchAll()
{
$select = $this->getSql()->select();
$select->join('works','artists.artist_id = artist_id ');
//create paginator object to display records
$paginator = new Paginator(
new DbSelect($select, $this->adapter, $this->resultSetPrototype)
);
return $paginator;
}
}
STEP 3> In controller I defined the following code
public function searchAction()
{
$request = $this->getRequest();
$paginator = $this->getWorksTable()->fetchAll();
// $paginator->setItemCountPerPage(12);
$vm = new ViewModel(array(
'poster' => $paginator,
));
$vm->setVariable('paginator', $paginator);
return $vm;
}
For statement $paginator->setItemCountPerPage(12); get error
Message:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'works'
Has anyone come across this error? Any ideas on how to resolve this?
you join works table to itself, mysql treat it as two separate tables joined but with same name, hence the error.
Use alias for table you join:
$select = $this->getSql()->select();
$select->join(array('w' => 'works'),'artists.artist_id = artist_id ');
but it looks like it is just typo there and table should be artists
There hasn't used artists table begin the query.and also didn't use works table on join.
use Zend\Paginator\Adapter\DbSelect;
use Zend\Db\Sql\Sql;
public function fetchAll()
{
$sql = new Sql($this->tableGateway->getAdapter());
$select = new Select();
$select->from("artists");
$select->columns(array('*'));
$select->join('works','artists.artist_id = works.artist_id',array('your_wanted_column_names,don't mention again artist_id here because there should be a error'));
$paginator = new Paginator(
new DbSelect($select, $this->adapter, $this->resultSetPrototype)
);
return $paginator;