Table name having additional underscores added - mysql

I have an API that grabs data from a table, serialises the data and then sends back via the service. The code is written using CakePHP using MySQL.
When I pass in the table name (such as RX_Scaled), an error is being returned that the table r_x_scaled can't be found (which don't surprise me, the table name in the database is rx_scaled).
My Model/Table for rx_scaled is defined like this
class rx_scaleds extends Table
{
public function initialize(array $config)
{
parent::initialize($config);
$this->table('rx_scaled');
}
With the Model/Entity
class rx_scaled extends Entity
{
}
My service API is set like this within the APIController.php file
public function getData($tablename, $id="", $filter = "-", $order = "-", $take = 0)
{
$the_table = $tablename;
$this->autoRender = false;
$table = TableRegistry::get($tablename);
$data = null;
switch (strtolower($the_table))
{
case "rx_scaled":
$data = $table->find();
echo $data;
break;
}
(this is truncated)
The odd thing is that this error does not occur in all tables.
I'm obviously not doing something correctly, but I'm not sure what

You named your table object rx_scaleds but then you pass RX_Scaled to the getData action
cake try not finding a Table Object named RX_Scaled try to inflect the name of the mysql table: so using cake's conventions RX_Scaled is mapped to r_x_scaled
So what can you do?
Use cake conventions
Name you table RxScaledsTable
class RxScaledsTable extends Table
Name you entity RxScaled
class RxScaled extends Entity
and pass the string 'RxScaled' to your action

Related

Symfony 4 - update JSON user roles

I have entity User with field roles:
/**
* #ORM\Column(name="roles", type="json")
*/
private $roles = [];
public function getRoles(): array
{
return $roles = $this->roles;
}
public function setRoles($roles): self
{
$this->roles[] = $roles;
return $this;
}
I want to add functionality to update user role from ROLE_ADMIN to ROLE_USER. I tried this in my controller but instead of replacing ROLE_ADMIN with ROLE_USER it inerts this: "ROLE_ADMIN""ROLE_USER". This is my controller:
public function updateuser(Request $request, $id) {
$entityManager = $this->getDoctrine()->getManager();
$usr = $this->getDoctrine()->getRepository(User::class)->find($id);
$usr->setRoles("ROLE_USER");
$entityManager->persist($usr);
$entityManager->flush();
First of all its best practice that every users has at least a default role like ROLE_USER. If you want to give users extra roles then you add them with beside ROLE_USER, like for example ROLE_ADMIN.
Now take a close look how arrays work in PHP. Let's take the code of you setter function setRoles.
When you write the value assignment like this $this->roles[] = $roles, then a value is added to the array . Thats why you in you code you have both roles inside you array now. The already existing ROLE_ADMIN and after the function call you added ROLE_USER.
When you write the value assignment like this $this->roles = $roles, then the whole array is overwritten with the new value.
Conclusion:
Thats how you code should look like if you want a simple solution:
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
Then you can call it like this:
$user->setRoles(['ROLE_USER']);
The setRoles function only accepts array.
So your code should change accordingly:
$usr->setRoles(["ROLE_USER"]);
Furthermore, if you want to store it as json, you can use json_encode:
$usr->setRoles(json_encode(["ROLE_USER"]));

Joining Two Tables to a Reference Table Laravel

I Have three tables
#1 Table timeline which is my reference table with an Auto incremented ID which is stored in column id
#2 timeline_videos
#3 timeline_else
What happens is on post if a video is uploaded with the post
it will go into Table #2 ,anything else goes into Table #3.
#2-3 have the Auto Increment Id from the Table timeline stored in a column pid
On query of The Timeline I need to join both tables data using id=pid
so I can use the rest of the Relational Data with the post.
I have done a bit of research and can't seem to find a method for doing so.
So far the code I have
Controller
$groupposts = timeline::where([
['owner','=',$owner],['id','<',$lastid],
])
->join('timeline_videos','timeline.id','=','timeline_videos.pid')
//->join('timeline_else','timeline.id','=','timeline_else.pid')
->orderBy('id','desc')
->limit(5)
->get();
This works with no errors with the second Join commented out but I need to also grab the timeline_else data .
Update --
I have now decided to use Eloquent Relationships to join the tables,
my question now is what type of relationship do I have between the
tables?
I realize it basically needs to be able to switch between two tables to
grab data based on the fact that timeline_videos and timeline_else will not be "JOIN" but separated by type .
The tables need to Join with table #1 timeline based on a column I now have named type for clarifying where to look and matching/joining using the id = pid
You can use relationships.
it sounds like timelines has many videos and has many video failures
https://laravel.com/docs/5.5/eloquent-relationships#one-to-many
you would have a model for each table and set up the relationships
timelines model:
public function videos()
{
return $this-> hasMany('App\Videos');
}
public function videoFailures()
{
return $this-> hasMany('App\videoFailures');
}
videos model:
public function timeline()
{
return $this->belongsTo('App\Timelines');
}
videos failures model:
public function timeline()
{
return $this->belongsTo('App\Timelines');
}
You can then go:
$timeLine = Timmeline::find($id);
to find videos of the time lines you would do:
$videos = $timeLine->videos();
to find else:
$videoElse = $timeLine-> videoFailures();
By using some of what Parker Dell supplied and a bit more trial and error
My Models Looks like
timeline
class timeline extends Model
{
protected $table ='timeline';
public $timestamps = false;
public function videos()
{
return $this->hasMany('App\timeline_videos','pid','id');
}
public function else()
{
return $this->hasMany('App\timeline_ect','pid','id');
}
}
timeline_ect.php ,I changed the name of the table
class timeline_ect extends Model
{
protected $table='timeline_ect';
public $timestamps = false;
public function timeline()
{
return $this->belongsTo('App\Models\timeline','pid','id');
}
}
timeline_videos
class timeline_videos extends Model
{
protected $table='timeline_videos';
public $timestamps = false;
public function timeline()
{
return $this->belongsTo('App\timeline','id','pid');
}
}
Then Lastly my Controller
$timeline = timeline::with('videos','else')
->orderBy('id','desc')
->limit(5)
->get();
So far no Problem query is correct.

Getting Form Data in edit-view with JTable which is joined?

i'm stuck with a problem of joined tables and retrieving Form-Data how it "should be" in best-practise-terms of Joomla!
I'm following the Joomla!-standards as far as my knownledge reaches, and the goal is to write this component "as if" it was native Joomla!-Code.
So what i have is the following COM_COMPONENT\models\release.php
<?php
defined('_JEXEC') or die;
class DojoMusicLibraryModelRelease extends JModelAdmin
{
public function getTable( $type = 'Releases', $prefix = 'DojoMusicLibraryTable', $config = array() )
{
return JTable::getInstance($type, $prefix, $config);
}
public function getForm( $data = array(), $loadData = true )
{
$options = array('control' => 'jform', 'load_data' => $loadData);
$form = $this->loadForm('releases', 'release', $options);
if (empty($form)) {
return false;
}
return $form;
}
protected function loadFormData()
{
$app = JFactory::getApplication();
$data = $app->getUserState('com_dojomusiclibrary.edit.release.data', array());
if (empty($data)) {
$data = $this->getItem();
}
return $data;
}
}
And in COM_COMPONENT\tables\releases.php
<?php
defined('_JEXEC') or die;
class DojoMusiclibraryTableReleases extends JTable
{
public $id;
public $title;
public $alias;
public $artist_id;
public $release_date_digital;
public $release_date_physical;
public $ean;
public $catalog_number;
public $promotional_text;
public $is_compilation;
public $format_id;
public $release_status;
// TODO: This tracklist should not be in this table, but only an id referring to it
public $tracklist;
public $created_at;
public $modified_at;
public $state;
public $publish_up;
public $publish_down;
public function __construct($db)
{
parent::__construct('#__dojomusiclibrary_releases', 'id', $db);
}
}
So now, as you can see from the comment in the latter code-example, the variable $tracklist is a field in the releases-table in my MySQL by now. As i got a "repeatable"-field-type, there is JSON inside of that field, and it works so far.
But the component is meant to hold another MySQL-table called "tracks", which holds all tracks of all releases and should be joined by a tracklist-id to the releases table, so that we have the following three tables:
releases (holds all the data, that is strictly bound to a single release/album/ep...)
tracklists (is an 1-to-m relation table, that has a tracklist_id, which is joined with the release and joins all single track_ids that belong to the tracklist)
tracks (holds all the track data, such as track_title, duration, genre and so on, while every track has an unique id, which can be joined to the tracklists)
As you can see this is getting more and more complex (especially if you consider that this is not the only part of the component, where this kind of joining tables for a single JForm will be needed).
Excerpt from the COM_COMPONENT\models\forms\release.xml
<!-- CATALOG NUMBER -->
<field name="catalog_number" type="text"
label="COM_DOJOMUSICLIBRARY_FORM_FIELD_CATALOG_NUMBER_LABEL"
description="COM_DOJOMUSICLIBRARY_FORM_FIELD_CATALOG_NUMBER_DESC" />
So now, as JForm seemingly expects something coming from the JTable since the release.xml binds the field-name to the naming of the variable in the JTable-Class, i do not really know how to deal with that, given that the data, that should be passed in one Form is coming from different tables.
So in summary i got different problems as far as i can see:
How can i manage to join tables for (best practice and right)
treatment of the JForm Standard in Joomla! ?
Since i use a repeatable-field-type to manage the tracklist, data will be stored into a JSON and saved to the database in only one field.
I need this repeatable solution since every release has n tracks with more than one information (track_no, title, genre...) and thanks to Joomla there is finally a native way to handle such cases.
BUT: Before saving them to the database the JSON must be split up into it's single values and be assigned to the proper fields in the tracks-table.
Okay... I know this is a huuuuuge question maybe... but since i'm totally stuck, I'd be happy about any advice for at least one of the issues :D
Thanks in advance :)

forcing auto-increment id in sonata admin custom clone action

I'm making a clone action in sonata admin--following the recommendations of Sonata docs:
<?php // src/Acme/DemoBundle/Controller/CRUDController.php
namespace Acme\DemoBundle\Controller;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
class CRUDController extends Controller
{
public function cloneAction()
{
$id = $this->get('request')->get($this->admin->getIdParameter());
$object = $this->admin->getObject($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
$clonedObject = clone $object;
$clonedObject->setName($object->getName()." (Clone)");
$this->admin->create($clonedObject);
$this->addFlash('sonata_flash_success', 'Cloned successfully');
return new RedirectResponse($this->admin->generateUrl('list'));
}
}
after setting an id on the $clonedobject I get a DBAL exception. primary keys with same id not allowed--
I've tried setting a unique id
no id with the hope that auto increment in my schema would force ++
thanks for your help
Geert is right, setting the id to null is the way to go with Doctrine.
However, rather than having to implement a setId method in your object, you may as well override the __clone method as follows:
public function __clone()
{
parent::__clone();
$this->id = null;
$this->name .= " (Clone)";
}
See How to re-save the entity as another row in Doctrine 2
I think the easy solution is to set your id to null and doctrine will generate an id for you while creating the cloned object...
$clonedObject = clone $object;
$clonedObject->setId(NULL);
$clonedObject->setName($object->getName()." (Clone)");

Yii model: Dynamic table relations

Table.linkedIndex is related to LinkedIndex.ID. The value of the field LinkedIndex.TableName is either Linked1 or Linked2 and defines which of these tables is related to a row in Table.
Now i want to make a dynamical link with Yii models so that i can easily get from a Table row to the corresponding Linked1 or Linked2 row:
Table.linkedID = [LinkedIndex.TableName].ID
Example
Table values:
LinkedIndex values:
Now I should get the row from Linked2 where ID=2:
$model = Table::model()->findByPk(0);
$row = $model->linked;
Model
In the model Table, I tried to make the relation to the table with the name of the value of linkedIndex.TableName:
public function relations()
{
return array(
'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
'linked' => array(
self::HAS_ONE,
'linkedIndex.TableName',
array('ID' => 'linkedID'),
)
)
}
But then I get the error:
include(linkedIndex.TableName.php) [function.include]: failed to open stream: No such file or directory
Is there any way to make a dynamic relation Table.linkedID -> [LinkedIndex.TableName].ID with Yii Models?
Per the Yii docs here:
http://www.yiiframework.com/doc/api/1.1/CActiveRecord#relations-detail
I'd suggest using self::HAS_ONE instead (unless there can be multiple rows in LinkedIndex with the same ID - although from the looks of above, I doubt that's the case).
You can link tables together that have different keys by following the schema:
foreign_key => primary_key
In case you need to specify custom PK->FK association you can define it as array('fk'=>'pk'). For composite keys it will be array('fk_c1'=>'pk_с1','fk_c2'=>'pk_c2').
so in your case:
public function relations(){
return array(
'linkedIndex' => array(self::HAS_ONE, 'LinkedIndex', array('ID' => 'linkedIndex')),
);
}
where LinkedIndex is the class name for the LinkedIndex model (relative to your Table model - i.e. same folder. You could change that, of course) and array('ID' => 'linkedIndex') specifies the relationship as LinkedIndex.ID = Table.linkedIndex.
Edit
Looking at your updated example, I think you're misunderstanding how the relations function works. You're getting the error
include(linkedIndex.TableName.php) [function.include]: failed to open stream: No such file or directory
because you're trying to create another relation here:
'linked' => array(
self::BELONGS_TO,
'linkedIndex.TableName',
array('ID' => 'linkedID'),
)
This part: linkedIndex.TableName refers to a new model class linkedIndex.TableName, so Yii attempts to load that class' file linkedIndex.TableName.php and throws an error since it doesn't exist.
I think what you're looking for is to be able to access the value TableName within the table LinkedIndex, correct? If so, that's accessible from within the Table model via:
$this->linkedIndex->TableName
This is made possible by the relation we set up above. $this refers to the Table model, linkedIndex refers to the LinkedIndex relation we made above, and TableName is an attribute of that LinkedIndex model.
Edit 2
Per your comments, it looks like you're trying to make a more complex relationship. I'll be honest that this isn't really the way you should be using linking tables (ideally you should have a linking table between two tables, not a linking table that says which 3rd table to link to) but I'll try and answer your question as best as possible within Yii.
Ideally, this relationship should be made from within the LinkedIndex model, since that's where the relationship lies.
Since you're using the table name as the linking factor, you'll need to create a way to dynamically pass in the table you want to use after the record is found.
You can use the LinkedIndex model's afterFind function to create the secondary link after the model is created within Yii, and instantiate the new linked model there.
Something like this for your LinkedIndex model:
class LinkedIndex extends CActiveRecord{
public $linked;
public static function model($className = __CLASS__){
return parent::model($className);
}
public function tableName(){
return 'LinkedIndex';
}
public function afterFind(){
$this->linked = new Linked($this->TableName);
parent::afterFind();
}
//...etc.
}
The afterFind instantiates a new Linked model, and passes in the table name to use. That allows us to do something like this from within the Linked model:
class Linked extends CActiveRecord{
private $table_name;
public function __construct($table_name){
$this->table_name = $table_name;
}
public static function model($className = __CLASS__){
return parent::model($className);
}
public function tableName(){
return $this->table_name;
}
//...etc.
}
which is how we dynamically create a class with interchangeable table names. Of course, this fails of the classes need to have separate operations done per-method, but you could check what the table_name is and act accordingly (that's pretty janky, but would work).
All of this would result in being to access a property of the linked table via (from within the Table model):
$this->linkedIndex->linked->foo;
Because the value of LinkedIndex.TableName and Table.linkedID is needed to get the values, I moved the afterFind, suggested by M Sost, directly into the Table-Class and changed its content accordingly. No more need for a virtual model.
class Table extends CActiveRecord {
public $linked; // Needs to be public, to be accessible
// ...etc.
public function afterFind() {
$model = new $this->linkedIndex->TableName;
$this->linked = $model::model()->findByPk( $this->linkedID );
parent::afterFind();
}
// ...
}
Now I get the row from Linked2 where ID=2:
$model = Table::model()->findByPk(0);
$row = $model->linked;