TYPO3 6.2 get Properties with values of Table - properties

I have the following problem: When I use a Model/Repository with a different mapping, I don't get any property and values.
I've mapped the Repository to fetch the data from table sys_files.
I do get the UID, I also do get the PID. Unfortunately, I do not get any other property or the value.
My Repository is a simple Repository mapped to sys_files.
Unfortunately, I do not get any orther property.
Thanks a lot.
Greetz

Have you defined the mapping in the ext_typoscript_setup.txt?
config.tx_extbase {
persistence {
classes {
Vendor\Package\Domain\Model\MyModel {
mapping {
tableName = sys_file
}
}
}
}
}
You also need to assign the needed fields in your domain model.
namespace Vendor\Package\Domain\Model;
class MyModel
{
/**
* #var string
*/
protected $identifier;
public function getIdentifier()
{
return $this->identifier;
}
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
}
}

There is a checklist when you mapping a model to a table:
1. Create the ext_typoscript_setup.txt file in the extension root path.
There you have to write the following code:
config.tx_extbase{
persistence {
classes {
YourModel.mapping{
table = table_you_want_to_map
}
}
}
}
Avoid to add backslash before model namespace
3. Clear cache from install tool. If nothing happens, then, try to delete the typo3temp/autoload folder.
4. The fields from the model should be camelCase.
Example of field: field_name in your model will be fieldName
5. Check the getters in your model.

Okay, problem solved - almost.
I can't get hash values. I don't know why but it is how it is.
I get the values of each column except "identifier_hash", "folder_hash". These attributes are always NULL.
Now I only have to make a new file_reference record in my db when I add a new relation.

Related

Laravel relationship with custom method

Table project:
project_id (int)
requestor_id (uuid)
Table requestor:
requestor_id (uuid)
Model Project:
public function requestor() {
return $this->hasOne('App\Models\Requestor', 'requestor_id', 'requestor_id');
}
Model Requestor has one method:
// this method return object users info from ldap
public function getLdapAttribute() {
$ldapWrapper = new LdapWrapper();
return $ldapWrapper->checkIfUuidExists($this->requestor_id, true);
}
Select all projects with requestor relationship:
$query = (new Project)->newQuery()->with(['requestor'])->get();
And Question is:
How can I select all projects with requestor relationship and on every requestor object call method getLdapAttribute and return all as one object?
Thank you very much :)
You can put the name of that "Ldap" attribute in the $appends array of the App\Requestor Class and Eloquent will automatically append a property named ldap with the value ,of the returned for the getLdapAttribute method.
Link to the Official Laravel Documentation for this Eloquent feature !
As SQL query of getLdapAttribute method is not specified, we can fetch projects first, and then iterate over and get that attribute.
If SQL query of getLdapAttribute is given then we can get all the data in one query (here we get attributes after the first query of fetching projects).
$projects = Project::with(['requestor'])
->get()
->each(function ($project) {
$project->requestor->getLdapAttribute();
});

Yii2 REST API relational data return

I've set up Yii2 REST API with custom actions and everything is working just fine. However, what I'm trying to do is return some data from the API which would include database relations set by foreign keys. The relations are there and they are actually working correctly. Here's an example query in one of the controllers:
$result = \app\models\Person::find()->joinWith('fKCountry', true)
->where(..some condition..)->one();
Still in the controller, I can, for example, call something like this:
$result->fKCountry->name
and it would display the appropriate name as the relation is working. So far so good, but as soon as I return the result return $result; which is received from the API clients, the fkCountry is gone and I have no way to access the name mentioned above. The only thing that remains is the value of the foreign key that points to the country table.
I can provide more code and information but I think that's enough to describe the issue. How can I encode the information from the joined data in the return so that the API clients have access to it as well?
Set it up like this
public function actionYourAction() {
return new ActiveDataProvider([
'query' => Person::find()->with('fKCountry'), // and the where() part, etc.
]);
}
Make sure that in your Person model the extraFields function includes fKCountry. If you haven't implemented the extraFields function yet, add it:
public function extraFields() {
return ['fKCountry'];
}
and then when you call the url make sure you add the expand param to tell the action you want to include the fkCountry data. So something like:
/yourcontroller/your-action?expand=fKCountry
I managed to solve the above problem.
Using ActiveDataProvider, I have 3 changes in my code to make it work.
This goes to the controller:
Model::find()
->leftJoin('table_to_join', 'table1.id = table_to_join.table1_id')
->select('table1.*, table_to_join.field_name as field_alias');
In the model, I introduced a new property with the same name as the above alias:
public $field_alias;
Still in the model class, I modified the fields() method:
public function fields()
{
$fields = array_merge(parent::fields(), ['field_alias']);
return $fields;
}
This way my API provides me the data from the joined field.
use with for Eager loading
$result = \app\models\Person::find()->with('fKCountry')
->where(..some condition..)->all();
and then add the attribute 'fkCountry' to fields array
public function fields()
{
$fields= parent::fields();
$fields[]='fkCountry';
return $fields;
}
So $result now will return a json array of person, and each person will have attribute fkCountry:{...}

Nhibernate mapping at run time

I am developing a site in which nhibernate is using. that is working fine for static mapping. but problem that i apply this application on existing database. so is there any way that mapping of classes took place at run time. i mean user provide tables and column names for mapping. Thanks
From your question I interpret you saying that the POCO classes exists, but you don't know the table or column names at build time.
So, if you already had this class:
public class MyGenericClass
{
public virtual long Id { get; set; }
public virtual string Title { get; set; }
}
You could bind it to a table and columns at runtime:
string tableName; // Set somewhere else by user input
string idColumnName; // Set somewhere else by user input
string titleColumnName; // Set somewhere else by user input
var configuration = new NHibernate.Cfg.Configuration();
configuration.Configure();
var mapper = new NHibernate.Mapping.ByCode.ModelMapper();
mapper.Class<MyGenericClass>(
classMapper =>
{
classMapper.Table(tableName);
classMapper.Id(
myGenericClass => myGenericClass.Id,
idMapper =>
{
idMapper.Column(idColumnName);
idMapper.Generator(Generators.Identity);
}
);
classMapper.Property(c => c.Title,
propertyMapper =>
{
propertyMapper.Column(titleColumnName);
}
);
}
);
ISessionFactory sessionFactory = configuration.BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
////////////////////////////////////////////////////////////////////
// Now we can run an SQL query over this newly specified table
//
List<MyGenericClass> items = session.QueryOver<MyGenericClass>().List();
I don't think that could be possibly with NHibernate, but you could use a workaround.
You could use a view instead a table for the NHibernate mapping.
And in runtime, you could create that View or update it with the especified user mapping you need.
For example, you define a mapping in NHibernate to a view named ViewMapped with two columns Name and Mail.
And in the other hand, the user has a table with three columns Name, SecondName, EMail.
you can create a view on runtime with the following select:
(SELECT Name + ' ' + SecondName as Name, EMail as Mail FROM tableName) AS ViewMapped
I hope that helps you, or at least leads you to a solution.

Handling uuid pk column in yii

I'm using UUID's as PK in my tables. They're stored in a BINARY(16) MySQL column. I find that they're being mapped to string type in YII. The CRUD code I generate breaks down though, because these binary column types are being HTML encoded in the views. Example:
<?php echo
CHtml::link(CHtml::encode($data->usr_uuid), /* This is my binary uuid field */
array('view', 'id'=>$data->usr_uuid)); ?>
To work around this problem, I overrode afterFind() and beforeSave() in my model where I convert the values to/from hex using bin2hex and hex2bin respectively. See this for more details.
This takes care of the view problems.
However, now the search on PK when accessing a url of the form:
http://myhost.com/mysite/user/ec12ef8ebf90460487abd77b3f534404
results in User::loadModel($id) being called which in turn calls:
User::model()->findByPk($id);
This doesn't work since the SQL is being generated (on account of it being mapped to php string type) is
select ... where usr_uuid='EC12EF8EBF90460487ABD77B3F534404'
What would have worked is if I could, for these uuid fields change the condition to:
select ... where usr_uuid=unhex('EC12EF8EBF90460487ABD77B3F534404')
I was wondering how I take care of this problem cleanly. I see one possiblity - extend CMysqlColumnSchema and override the necessary methods to special case and handle binary(16) columns as uuid type.
This doesn't seem neat as there's no support for uuid natively either in php (where it is treated as string) or in mysql (where I have it as binary(16) column).
Does anyone have any recommendation?
If you plan using it within your own code then I'd create my own base AR class:
class ActiveRecord extends CActiveRecord
{
// ...
public function findByUUID($uuid)
{
return $this->find('usr_uuid=unhex(:uuid)', array('uuid' => $uuid));
}
}
If it's about using generated code etc. then customizing schema a bit may be a good idea.
I used the following method to make working with uuid (binary(16)) columns using Yii/MySQL possible and efficient. I mention efficient, because I could have just made the column a CHAR(32) or (36) with dashes, but that would really chuck efficient out of the window.
I extended CActiveRecord and added a virtual attribute uuid to it. Also overloaded two of the base class methods getPrimaryKey and setPrimaryKey. With these changes most of Yii is happy.
class UUIDActiveRecord extends CActiveRecord
{
public function getUuid()
{
$pkColumn = $this->primaryKeyColumn;
return UUIDUtils::bin2hex($this->$pkColumn);
}
public function setUuid($value)
{
$pkColumn = $this->primaryKeyColumn;
$this->$pkColumn = UUIDUtils::hex2bin($value);
}
public function getPrimaryKey()
{
return $this->uuid;
}
public function setPrimaryKey($value)
{
$this->uuid = $value;
}
abstract public function getPrimaryKeyColumn();
}
Now I get/set UUID using this virtual attribute:
$model->uuid = generateUUID(); // return UUID as 32 char string without the dashes (-)
The last bit, is about how I search. That is accomplished using:
$criteria = new CDbCriteria();
$criteria->addCondition('bkt_user = unhex(:value)');
$criteria->params = array(':value'=>Yii::app()->user->getId()); //Yii::app()->user->getId() returns id as hex string
$buckets = Bucket::model()->findAll($criteria);
A final note though, parameter logging i.e. the following line in main.php:
'db'=>array(
...
'enableParamLogging' => true,
);
Still doesn't work, as once again, Yii will try to html encode binary data (not a good idea). I haven't found a workaround for it so I have disabled it in my config file.

Yii form and model for key-value table

I have a table which has only two column key-value. I want to create a form which allow user insert 3 pair of key-value settings.
Do I need pass 3 different models to the view? Or is there any possible way to do this?
Check out this link:
http://www.yiiframework.com/doc/guide/1.1/en/form.table
This is considered best form in Yii for updating for creating multiple models.
In essence, for creation you can create a for loop generate as many inputs a you wish to have visible, and in your controller loop over the inputs to create new models.
View File:
for ( $settings as $i=>$setting ) //Settings would be an array of Models (new or otherwise)
{
echo CHtml::activeLabelEx($setting, "[$i]key");
echo CHtml::activeLabelEx($setting, "[$i]key");
echo CHtml::error($setting, "[$i]key");
echo CHtml::activeTextField($setting, "[$i]value");
echo CHtml::activeTextField($setting, "[$i]value");
echo CHtml::error($setting, "[$i]value");
}
Controller actionCreate:
$settings = array(new Setting, new Setting, new Setting);
if ( isset( $_POST['Settings'] ) )
foreach ( $settings as $i=>$setting )
if ( isset( $_POST['Setttings'][$i] ) )
{
$setting->attributes = $_POST['Settings'][$i];
$setting->save();
}
//Render View
To update existing models you can use the same method but instead of creating new models you can load models based on the keys in the $_POST['Settings'] array.
To answer your question about passing 3 models to the view, it can be done without passing them, but to validate data and have the correct error messages sent to the view you should pass the three models placed in the array to the view in the array.
Note: The example above should work as is, but does not provide any verification that the models are valid or that they saved correctly
I'm going to give you a heads up and let you know you could potentially make your life very complicated with this.
I'm currently using an EAV patterned table similar to this key-value and here's a list of things you may find difficult or impossible:
use CDbCriteria mergeWith() to filter related elements on "value"s in the event of a search() (or other)
Filtering CGridView or CListView
If this is just very straight forward key-value with no related entity aspect ( which I'm guessing it is since it looks like settings) then one way of doing it would be:
create a normal "Setting" CActiveRecord for your settings table (you will use this to save entries to your settings table)
create a Form model by extending CFormModel and use this as the $model in your form.
Add a save() method to your Form model that would individually insert key-value pairs using the "Setting" model. Preferably using a transaction incase a key-value pair doesn't pass Settings->validate() (if applicable)
optionally you may want to override the Form model's getAttributes() to return db data in the event of a user wanting to edit an entry.
I hope that was clear enough.
Let me give you some basic code setup. Please note that I have not tested this. It should give you a rough idea though.:
Setting Model:
class Setting extends CActiveRecord
{
public function tableName()
{
return 'settings';
}
}
SettingsForm Model:
class SettingsForm extends CFormModel
{
/**
* Load attributes from DB
*/
public function loadAttributes()
{
$settings = Setting::model()->findAll();
$this->setAttributes(CHtml::listData($settings,'key','value'));
}
/*
* Save to database
*/
public function save()
{
foreach($this->attributes as $key => $value)
{
$setting = Setting::model()->find(array('condition'=>'key = :key',
'params'=>array(':key'=>$key)));
if($setting==null)
{
$setting = new Setting;
$setting->key = $key;
}
$setting->value = $value;
if(!$setting->save(false))
return false;
}
return true;
}
}
Controller:
public function actionSettingsForm()
{
$model = new Setting;
$model->loadAttributes();
if(isset($_POST['SettingsForm']))
{
$model->attributes = $_POST['SettingsForm'];
if($model->validate() && $model->save())
{
//success code here, with redirect etc..
}
}
$this->render('form',array('model'=>$model));
}
form view :
$form=$this->beginWidget('CActiveForm', array(
'id'=>'SettingsForm'));
//all your form element here + submit
//(you could loop on model attributes but lets set it up static for now)
//ex:
echo $form->textField($model,'fieldName'); //fieldName = db key
$this->endWidget($form);
If you want further clarification on a point (code etc.) let me know.
PS: for posterity, if other people are wondering about this and EAV they can check the EAV behavior extention or choose a more appropriate DB system such as MongoDb (there are a few extentions out there) or HyperDex