Create a module that implement a new fieldType in Drupal 8 with a form that containt a field image - module

I need create a new fieldType into a module, in the backoffice appear like exist the created fieldType, but in the fieldType I need set a two fields, a image and a url (like string), and I found a sql error when I create a new field from the current type in drupal backoffice, because I cannot found the correct file type for the image, or the way to do it.
I have the structure like this:
[module-name]/
+ src/
| + Plugin/
| | + Field/
| | | + FieldFormatter/
| | | + FieldType/
| | | + FieldWidget/
In the module file "FieldType/[module-name]Type.php" I have the function to create the schema:
/**
* {#inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
// $schema = parent::schema($field_definition);
$schema = [];
$schema['columns']['url_op'] = [
'description' => 'The url of the cropped image',
'type' => 'varchar',
'length' => 255,
];
$schema['columns']['image_op'] = [
'type' => 'managed_file',
'description' => 'The image to crope',
'upload_location' => 'public://openseadragon-int',
];
$schema['indexes']['image_op'] = ['image_op'];
return $schema;
}
The sql error is:
Ha habido un problema creando el campo Openseadragon:
Exception thrown while performing a schema update.
SQLSTATE[42000]: Syntax error or access violation: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL DEFAULT NULL COMMENT 'The image to crope', PRIMARY KEY (`entity_id`, `dele' at line 9: CREATE TABLE {node__field_openseadragon} ( `bundle` VARCHAR(128) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance', `deleted` TINYINT NOT NULL DEFAULT 0 COMMENT 'A boolean indicating whether this data item has been deleted', `entity_id` INT unsigned NOT NULL COMMENT 'The entity id this data is attached to', `revision_id` INT unsigned NOT NULL COMMENT 'The entity revision id this data is attached to', `langcode` VARCHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '' COMMENT 'The language code for this data item.', `delta` INT unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields', `field_openseadragon_url_op` VARCHAR(255) NULL DEFAULT NULL COMMENT 'The url of the cropped image', `field_openseadragon_image_op` NULL DEFAULT NULL COMMENT 'The image to crope', PRIMARY KEY (`entity_id`, `deleted`, `delta`, `langcode`), INDEX `bundle` (`bundle`), INDEX `revision_id` (`revision_id`), INDEX `field_openseadragon_image_op` (`field_openseadragon_image_op`) ) ENGINE = InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT 'Data storage for node field field_openseadragon.'; Array ( )

Related

Why this PDO parametrized query behave "strangely"?

Here i have edited my original question.
I have alswo answered it, in my next message.
I'm trying to get results from MySQL with parametrized php PDO query, but thing behaves strangley. I dont know if it is a bug, or I am doing something wrong or not seeing something obvious.
Lets suppose there are these two tables in database
CREATE TABLE `users` (
`user_id` int(11) NOT NULL PRIMARY KEY
)
CREATE TABLE `users_contacts` (
`contact_id` int(11) NOT NULL PRIMARY KEY ,
`user_id` int(11) DEFAULT NULL,
`type` varchar(45) DEFAULT NULL,
`value` varchar(255) DEFAULT NULL
)
Fill them with minimal data :
INSERT INTO `users` (`user_id`) VALUES (125);
INSERT INTO `users_contacts` (`contact_id`, `user_id`, `type`, `value`)
VALUES(11432, 125, 'email', 'losleyTyped#offten.stinks'),
(11433, 125, 'phone', '1234567'),
(564, 125, 'unit', '910');
And then you try to fetch data like this
$db_name = "";
$db_user = "";
$db_pass = "";
$db_pdo = new pdo("mysql:host=localhost;dbname=$db_name","$db_user","$db_pass");
$user = 125;
$user_unit_btm = 900;
$user_unit_top = $user_unit_btm + 100;
$upload_user = $db_pdo -> prepare("SELECT K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id AND
K.user_id = O.user_id AND
K.type = 'unit' AND
K.value >= :unit_btm AND
K.value < :unit_top
");
$upload_user -> execute( [":user_id" => $user,
":unit_btm" => $user_unit_btm,
":unit_top" => $user_unit_top
]
);
$upload_user = $upload_user -> fetch(PDO::FETCH_ASSOC);
var_dump($upload_user);
var_dump will return false, but there is no error(err is 0000)
I have reduced the problem, and find that only one parameter ":organization" is problematic and cause for bizare behevior.
But if you replace " K.value < :unit_top "
with variable $user_unit_top
" K.value < $user_unit_top "
Then, query returns result!
Same thing if i replace " K.value < :unit_top " with literal 1000,
" K.value < 100"
Then query returns result!
Why is this happening?
As mentioned in my comment to your answer.
The PHP documentation on PDOStatement::execute states.
An array of values with as many elements as there are bound parameters in the SQL statement being executed. All values are treated as PDO::PARAM_STR.
Source: https://www.php.net/manual/en/pdostatement.execute.php
Additionally PDOStatement::fetch() returns false when there are no more results or upon failure.
The return value of this function on success depends on the fetch type. In all cases, FALSE is returned on failure.
Example https://3v4l.org/NVECJ
$pdo = new \PDO('sqlite::memory:', null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
$pdo->query('CREATE TABLE foo(id INTEGER)');
$stmt = $pdo->prepare('SELECT * FROM foo');
$stmt->execute();
var_dump($stmt->fetch());
//bool(false)
If you need to explicitly define a data type, other than PDO::PARAM_STR for the parameter being sent to MySQL, you would use PDOStatement::bindParam or PDOStatement::bindValue
Example:
$upload_user = $db_pdo->prepare('SELECT
K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id
AND K.user_id = O.user_id
AND K.type = \'unit\'
AND K.value >= :unit_btm
AND K.value < :unit_top');
$upload_user->bindValue(':user_id', $user, PDO::PARAM_INT);
$upload_user->bindValue(':unit_btm', $user_unit_btm, PDO::PARAM_INT);
$upload_user->bindValue(':unit_top', $user_unit_top, PDO::PARAM_INT);
$upload_user->execute();
An alternative would be to force data type casting on the parameter in the query.
$upload_user = $db_pdo->prepare('SELECT
K.value AS unit
FROM users AS O,
users_contacts AS K
WHERE O.user_id = :user_id
AND K.user_id = O.user_id
AND K.type = \'unit\'
AND K.value >= (:unit_btm - 0)
AND K.value < (:unit_top - 0)'); //CAST(:unit_top AS SIGNED)
$upload_user->execute([
':user_id' => $user,
':unit_btm' => $user_unit_btm,
':unit_top' => $user_unit_top
]);
Another contributing factor to your issue, is that MySQL will perform an automatic conversion to the column's data type for the comparison. Where other RDMBS, like PostgreSQL and SQLite3 do not perform the same conversions.
When an operator is used with operands of different types, type
conversion occurs to make the operands compatible. Some conversions
occur implicitly. For example, MySQL automatically converts strings to
numbers as necessary, and vice versa.
Source: https://dev.mysql.com/doc/refman/5.7/en/type-conversion.html
Since your initial column data type was VARCHAR, this resulted in the following from your testing.DB Fiddle
Initial query as PDOStatement::execute([1000]).
SELECT IF('910' > '1000', 'fail', 'pass') AS if_str_to_str;
| if_str_to_str |
| ------------- |
| fail |
Manually supplying integer to the Query
SELECT IF('910' > 1000, 'fail', 'pass') AS if_str_to_int;
| if_str_to_int |
| ------------- |
| pass |
After changing the database column data type and using PDOStatement::execute([1000])
SELECT IF(910 > '1000', 'fail', 'pass') AS if_int_to_str;
| if_int_to_str |
| ------------- |
| pass |
Using PDOStatement::bindValue(':param', '1000', PDO::PARAM_INT) or ('1000' - 0)
SELECT IF('910' > CAST('1000' AS SIGNED), 'fail', 'pass') AS if_str_to_typecast_int;
| if_str_to_typecast_int |
| ---------------------- |
| pass |
Here is an answer if somebody else find him self with similar problem
Why is this happening?
I think it is because Php or MySQL automatic type recognition/casting
Take a look of the table users_contacts the column named 'value' is of type VARCHAR (because the table is something like EAV data model).
In prepared query from my question on this line
K.value < :unit_top
PHP/MySQL is supposing that parameter :unit_top is the same datatype as K.value column (VARCHAR) so it compares-collation them like strings ???, and the string "910" is later then "1000".
If you replace parameter ":unit_top" with variable $user_unit_top
K.value < $user_unit_top
or a literal
K.value < 1000
Then Php is doing numeric comparison, and "1000" is bigger then "910"
*If you change table users_contacts column named 'value' from VARCHAR to INT then the
K.value < :unit_top
comparison will be numeric
I think this is very inconsistent behavior, because if you do the following
$a = "1000";
$b = " 910";
var_dump($a < $b);
PHP will do automatic type casting and then numeric commparison, ...
Am I wrong ?

Optional column update if provided value for column is not null

I have following table:
CREATE TABLE IF NOT EXISTS categories
(
id SERIAL PRIMARY KEY,
title CHARACTER VARYING(100) NOT NULL,
description CHARACTER VARYING(200) NULL,
category_type CHARACTER VARYING(100) NOT NULL
);
I am using pg-promise, and I want to provide optional update of columns:
categories.update = function (categoryTitle, toUpdateCategory) {
return this.db.oneOrNone(sql.update, [
categoryTitle,
toUpdateCategory.title, toUpdateCategory.category_type, toUpdateCategory.description,
])
}
categoryName - is required
toUpdateCategory.title - is required
toUpdateCategory.category_type - is optional (can be passed or undefined)
toUpdateCategory.description - is optional (can be passed or undefined)
I want to build UPDATE query for updating only provided columns:
UPDATE categories
SET title=$2,
// ... SET category_type=$3 if $3 is no NULL otherwise keep old category_type value
// ... SET description=$4 if $4 is no NULL otherwise keep old description value
WHERE title = $1
RETURNING *;
How can I achieve this optional column update in Postgres?
You could coalesce between the old and the new values:
UPDATE categories
SET title=$2,
category_type = COALESCE($3, category_type),
description = COALESCE($4, description) -- etc...
WHERE title = $1
The helpers syntax is best for any sort of dynamic logic with pg-promise:
/* logic for skipping columns: */
const skip = c => c.value === null || c.value === undefined;
/* reusable/static ColumnSet object: */
const cs = new pgp.helpers.ColumnSet(
[
'title',
{name: 'category_type', skip},
{name: 'description', skip}
],
{table: 'categories'});
categories.update = function(title, category) {
const condition = pgp.as.format(' WHERE title = $1', title);
const update = () => pgp.helpers.update(category, cs) + condition;
return this.db.none(update);
}
And if your optional column-properties do not even exist on the object when they are not specified, you can simplify the skip logic to just this (see Column logic):
const skip = c => !c.exists;
Used API: ColumnSet, helpers.update.
See also a very similar question: Skip update columns with pg-promise.

laravel 5 SQLSTATE[42S22]: Column not found: 1054 Unknown column 'messages.sender_id' in 'having clause'

I am migrating my site from laravel 4.2 to laravel 5.0, and have been doing so for the past 4 days. After going through so many errors, the latest error I am facing is its throwing this exception:
PDOException in Connection.php line 292: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'messages.sender_id' in 'having clause'.
It was working find before migrating the site and I didn't change the database.
I have a JobsController named controller which is producing the error. Here is the function :
public function index()
{
$categories = Client::find(Auth::user()->id)->categories;
foreach ($categories as $category) {
$category_arr[] = $category->id;
}
$jobs = Job::leftJoin('messages', function($join)
{
$join->on('jobs.id', '=', 'messages.job_id')
->where('messages.sender_id', '=', getLoggedInId());
})
->whereIn('category_id', $category_arr)
->where('status', 1)
->where('request_for', 0)
->groupBy('jobs.id')
->havingRaw('messages.sender_id <> '.getLoggedInId().' or messages.sender_id is null')
->select(['jobs.*', 'messages.job_id', 'messages.sender_id'])
->orderBy('created_at', 'DESC')
->paginate(10);
$title = "Available Requests";
$this->layout = View::make('layouts.loggedin', compact('title'));
$this->layout->content = View::make('jobs/index', compact('jobs'));
}
Please help to solve this. Let me know if any other information is needed.
Here is the message table :
id int(11) NO PRI NULL auto_increment
message text NO NULL
sender_id int(11) NO NULL
receiver_id int(11) NO NULL
job_id int(11) NO NULL
created_at datetime NO NULL
updated_at datetime NO NULL

Cannot insert NULL values into database

We use JPA to load/persist our entities in a prostges database. In one case i must persist a entity with a native query. Heres is the code:
String sql = "INSERT INTO recording (id,creationdate,duration,endtime,filemaninfocomplete,lastupdated,packagesdeletetime,rcinfocomplete,"
+ "rcrecordingkept,recordstate,recordingtype,starttime,tenantid,recordingnode_id,transcription_id) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
Query query = getEntityManager().createNativeQuery(sql);
query.setParameter(1, recording.getId());
query.setParameter(2, new Date(), TemporalType.TIMESTAMP);
query.setParameter(3, recording.getDuration());
query.setParameter(4, recording.getEndtime(), TemporalType.TIMESTAMP);
query.setParameter(5, recording.isFileManInfoComplete());
query.setParameter(6, new Date(), TemporalType.TIMESTAMP);
query.setParameter(7, recording.getPackagesDeleteTime(), TemporalType.TIMESTAMP);
query.setParameter(8, recording.isRcInfoComplete());
query.setParameter(9, recording.isRcRecordingKept());
query.setParameter(10,recording.getRecordState() != null ? recording.getRecordState().toString() : RecordState.DEFAULT);
query.setParameter(11,recording.getRecordingType()!= null ? recording.getRecordingType().toString() : null);
query.setParameter(12,recording.getStarttime(), TemporalType.TIMESTAMP);
query.setParameter(13,recording.getTenantId());
query.setParameter(14,recording.getRecordingNode() != null ? recording.getRecordingNode().getId() : null);
query.setParameter(15, recording.getTranscription() != null ? recording.getTranscription().getId() : null);
query.executeUpdate();
The insert works finde unless "getPackagesDeleteTime" returns null. In this case the following message ist shown:
Caused by: org.postgresql.util.PSQLException: FEHLER: Spalte »packagesdeletetime« hat Typ timestamp without time zone, aber der Ausdruck hat Typ character varying
Hinweis: Sie müssen den Ausdruck umschreiben oder eine Typumwandlung vornehmen.
Position: 252
(ie:
ERROR: column "packagesdeletetime" has type timestamp without time zone, but the expression is of type character varying
Hint: You must rewrite the expression or typecast.
)
Generated Statement looks like:
INSERT INTO recording(id,creationdate,duration,endtime,filemaninfocomplete,lastupdated,packagesdeletetime,rcinfocomplete,rcrecordingkept,recordstate,recordingtype,starttime,tenantid,recordingnode_id,transcription_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
bind => [0c850391-cae9-4ac2-9381-b252167fa239, 2013-04-18 08:38:00.704, 20240, 2013-04-18 08:37:24.131, false, 2013-04-18 08:38:00.704, null, false, true, DEFAULT, VOICE, 2013-04-18 08:37:03.891, f56251a7-44df-4151-aa0d-7c3fc538f621, null, null]
Some tips how i could solve the problem?
The corresponding field in the entity has to be annotated with:
#Column(nullable=true)
Also check the corresponding column in your table allows NULL (has no NOT NULL constraint).
If this doesn't help please post the code of your entity.

invalid yii relation HAS_MANY

i am having some throuble building a simple Poll application in Yii.
I have the following tables:
create table poll (
id integer not null auto_increment,
title varchar(255) not null,
views integer not null default 0,
created_at timestamp not null default NOW(),
PRIMARY KEY(id)
);
create table choice (
poll_id integer not null,
choice varchar(200) not null,
votes integer not null default 0
);
I have an ActiveRecord for Poll defined as:
class Poll extends CActiveRecord
{
...
public function relations()
{
return array(
'choices'=>array(self::HAS_MANY, 'Choice', 'poll_id'),
);
}
...
}
However when I use the following code:
$p = Poll::model()->findByPk($id)->with('choices')->findAll();
It gives me the traceback:
Invalid argument supplied for foreach()
#0
+ /home/william/scm/bmbraga/clickpoll/yii/framework/db/ar/CActiveFinder.php(791): CJoinElement->populateRecord(CJoinQuery, array("1", "0", "", "2011-02-28 13:11:41", ...))
#1
+ /home/william/scm/bmbraga/clickpoll/yii/framework/db/ar/CActiveFinder.php(736): CJoinElement->populateRecord(CJoinQuery, array("1", "0", "", "2011-02-28 13:11:41", ...))
#2
+ /home/william/scm/bmbraga/clickpoll/yii/framework/db/ar/CActiveFinder.php(395): CJoinElement->runQuery(CJoinQuery)
#3
+ /home/william/scm/bmbraga/clickpoll/yii/framework/db/ar/CActiveFinder.php(72): CJoinElement->find(CDbCriteria)
#4
+ /home/william/scm/bmbraga/clickpoll/yii/framework/db/ar/CActiveRecord.php(1242): CActiveFinder->query(CDbCriteria, true)
#5
+ /home/william/scm/bmbraga/clickpoll/yii/framework/db/ar/CActiveRecord.php(1323): CActiveRecord->query(CDbCriteria, true)
#6
+ /home/william/scm/bmbraga/clickpoll/poll/protected/controllers/PollController.php(156): CActiveRecord->findAll()
Anyone have any idea what i have been doing wrong? I am quite new to Yii
Thank you
Ok, i found out the problem.
The poll table needs a primary key.