extbase mapping to an existing table doesn't work - mapping

I've extended the pages table and now I want to use some of the data in a domain object called "Tags".
So I tried the following in the /Configuration/TypoScript/setup.txt:
plugin.myextension.persistence.classes.Tx_myextension_Domain_Model_Tag {
mapping {
tableName = pages
recordType = Tx_myextension_Domain_Model_Tag
columns {
tx_myextension_tag_name.mapOnProperty = name
uid.mapOnProperty = id
}
}
}
But It seems that the extension tries to access the table Tx_myextension_Domain_Model_Tag (which doesn't exist)
This is the error I receive:
Tx_Extbase_Persistence_Storage_Exception_SqlError`
Table 'tx_myextension_domain_model_tag' doesn't exist: SELECT tx_myextension_domain_model_tag.* FROM tx_myextension_domain_model_tag WHERE tx_myextension_domain_model_tag.id = '24' LIMIT 1
What have I done wrong?

Don't forget to include your extension typoscript template into your template ( template > edit whole template > include static templates ), otherwise your setup.txt is not evaluated.

To check which recordType(s) are acceptable use Configuration module in BE, in $TCA section find your table ([pages] in this case) and check type column (...[ctrl][type] - for pages it's 'doktype', which decides if page record is standard page or sysfolder etc.).
This column is tinyint(3) in database, so you can not write value 'Tx_myextension_Domain_Model_Tag' to it. Create in your ext new doktype identified by number and set recordType to it.
Optionaly you can just remove recordType from mapping config if page's type doesn't matter to you.

did you try "config.tx_extbase" instead of "plugin.myextension"?
Something like
config.tx_extbase.persistence.classes.Tx_MyExtension_Domain_Model_Tag.mapping.tableName = pages
works for me.

Tx_myextension_Domain_Model_Tag is the name of your object right ? But I guess this is not the name of the table you are trying to access. So my guess is that the name you are providing into the value "tableName" is wrong. What does "pages" contain ?

Have you specified the individual pages as recordtype Tx_myextension_Domain_Model_Tag ?
It's supposed to go into the doctype field of the pages table (therefore you'll need to change the mysql datatype of that field.
Otherwise Extbase doesn't know that this specific page is an extbase record and not a regular page.
See more about single table inheritance (STI) in Extbase: http://pascal-jungblut.com/blog/blog-post/2010/11/06/single-table-inheritance-in-extbase.html

do you do this in a typo3 call with eID?
here some configuration is not loaded ..
if yes, try if loading all configuration solves the problem:
...
$GLOBALS['TSFE'] = \t3lib_div::makeInstance('tslib_fe', $TYPO3_CONF_VARS, $_GET["id"], 0, true);
//$GLOBALS['TSFE'] = new $temp_TSFEclassName();
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->getCompressedTCarray();
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
...

Take care of the proper naming convention regarding FE-Plugins:
plugin.tx_myextension

Related

Umbraco - Get Property by type

I'm new to Umbraco, so this may not even be feasible. I've created my own Datatype using Archetype and want to be able to get an instance of that type on the page by type, not alias.
I know that I can do the following:
model.Content.GetPropertyValue("myAlias")
But I want to know if it's feasible to get the property by the type. Something along the lines of:
model.Content.GetPropertiesByType("TypeName")
which would return a list of controls on the page of that type?
Is this feasible?
It's possible, but not exactly straight forward.
Take a look at the available Umbraco Data Services - you'll need to retrieve the DataTypeDefinitions from the DataTypeService and retrieve the ContentType for the Model's IPublishedContent using the ContentTypeService.
Once you have these, you can match up the PropertyTypes on the ContentType with the retrieved DataTypeDefionitions based on the PropertyType's DataTypeDefinitionId.
The PropertyTypes have an Alias property which will match up with the Property Aliases on the Content itself.
You can use the content service if you get the id of the datatype you trying to find the multiples of from the url when you edit/create the datatype.
#foreach (var p in ApplicationContext.Current.Services.ContentService.GetById(Model.Content.Id).PropertyTypes.Where(p => p.DataTypeDefinitionId == -89))
{
<p>#p.DataTypeDefinitionId</p>
}

How to get ModelState Errors at runtime using Key added by ModeState.AddModelError( key,value)

I have added Model error from controller using
if( model property not selected)
{
ModelState.AddModelError("SelectionRequired","Please select atleast one value");
}
This error I am adding at many places in that same method but ultimately I want to show to user only one such message out of the ModelState errors collection.
For that purpose before returning to view I have to remove all similar messages except one.
How can i remove this messages using "SelectionRequired" i.e. key and not using "Please select atleast one value".This "SelectionRequired" is not a model property name is just a key we want to use.
I checked ModelState.Keys collection at runtime I don't see the "SelectionRequired" at all in those collection and also not even in ModelState.Values collection. Then where does this key *"SelectionRequired" goes ? and how to select errors based on it ?
is there any better way to do this ?
This might work:
var error = ModelState["SelectionRequired"].Errors.First();
ModelState["SelectionRequired"].Errors.Clear();
ModelState["SelectionRequired"].Errors.Add(error);

How to get HTML generated at runtime and control imagery based on host header and lookup table in .ASP.Net

There are 3 concepts each type of user loggin in. The imagery is controlled by a lookup table based on the host header. By this, I mean that there are several domain names that point to the same IP/web instance, and that instance serves up the content based on reading the host header.
What we are doing now by having all the HTML (not the code) stored in a table that is referenced by the host header lookup.
CAn somebody guide me on this requirement please? Thanks
There are probably better ways to deal with multi-tenancy but let's assume you can't change any of that. What you want is probably this
string domain = HttpContext.Current.Request.ServerVariables["HTTP_HOST"];
You could map this domain onto a customer Id and store this in the user's cookie and look up based on this, mapping as necessary. Or simply use domain directly for your table lookup.
Request.Url.Host
This will give you the domain name such as: "www.example.com". I would recommend to store records including "view name" and "domain". Then, on your action, I would imagine something like this:
var record = db.HostRecords.Where(r => r.Domain == Request.Url.Host).FirstOrDefault();
var view = "Page.cshtml";
if (record != null){
view = record.ViewName;
}
return View(view);

Creating Drop down list for a column which is defined as an Int in the SQL database - jqGrid ASP.NET MVC

I am using Entity Framework Database First approach in ASP.NET MVC.
I have created models from an existing database and everything works fine.
I am using jqGrid and trying to create a drop down list for a column which is defined as an Int in the database.
In the database, the values are either 0 or 1, so in the dropdown list I will have to show two values such as "Import" or "Export" based on whether it is 0 or 1.
Would I be able to handle this scenario in the jqGrid?
Please post any suggestions if you have!
I think you can handle this thing in colModal itself. there's is one option editOption you can specify with you colModal and based on the value you are getting from data you can specfy the text property of that column
In this case, the data for the grid should contain “One” or “Two” to be set in the column myname.
Now, with this setting
<script>
jQuery("#grid_id").jqGrid({
...
colModel : [ {name:'myname', edittype:'select', formatter:'select', editoptions:{value:"1:One;2:Two"}} ... ]
...
});
</script>
the data should contain the keys (“1” or “2”), but the value (“One”, or “Two”) will be displayed in the grid.
check this link for further help. You will get your answer. Because you didn't post your code(atleast you should have done that for ur that particular column) i can not say you are implementing the same way.

Apostrophe CMS: Engine Creation

I'm attempting to create a Product Engine for Apostrophe. I'm having trouble extending the Page Settings form, at the moment I want to add a simple textarea to add a synopsis to the page - eventually I want to add Product settings but I need to get the basics working first.
I've created a form and a settings partial, it's displaying fine and saving the data (with the help of a little hack - might not be correct). The trouble I'm having is when you edit a page the data is not being pulled back in to the form. To be honest I probably doing something fundamentally wrong but I lack experience in Symfony.
My table schema
ccProduct:
tableName: cc_product
actAs:
Timestampable: ~
columns:
page_id:
type: integer
notnull: true
synopsis:
type: text
relations:
Page:
class: aPage
local: page_id
foreign: id
type: one
onDelete: CASCADE
My form ccProductEngineForm.class.php
class ccProductEngineForm extends ccProductForm
{
public function __construct($object = null, $options = array(), $CSRFSecret = null)
{
// when editing the page the values are not show, this is an attempt to get it to work - it still doesn't :(
$page_id = sfContext::getInstance()->getRequest()->getParameter('id');
sfContext::getInstance()->getRequest()->setParameter('page_id', $page_id);
$ccProduct = Doctrine::getTable('ccProduct')->findOneByPageId($page_id);
if ($ccProduct) {
sfContext::getInstance()->getRequest()->setParameter('id', $ccProduct->getId());
}
// aPageForm object is passed in
parent::__construct(null, $options, $CSRFSecret); // construct normally
//$this->mergeForm(new aPageForm($object, $options, $CSRFSecret)); // merge the aPageForm - Nope, ignore it!?
}
public function setup() {
parent::setup();
$this->useFields(array('synopsis'));
$this->widgetSchema->setNameFormat('enginesettings[%s]');
$this->widgetSchema->setFormFormatterName('aPageSettings');
}
protected function doSave($con = null)
{
// page_id is missing! possible bug? BaseaActions.class.php ~ 520
$this->values['page_id'] = sfContext::getInstance()->getRequest()->getParameter('enginesettings[pageid]');
parent::doSave($con);
}
}
Thanks in advance for any help
EDIT:
Thanks for your answer Tom, I'll try to add a little more detail.
I was aware that a page object is passed into the Engine, but I wasn't exactly sure what do to with it - see my confused line of code:
//$this->mergeForm(new aPageForm($object, $options, $CSRFSecret)); // merge the aPageForm - Nope, ignore it!?
To clarify my 'product' is a page that uses the ccProduct engine. I now want to add extra information to that page. Does that make sense? In your words..
Are you trying to actually create a unique product that has its sole "home" on a product engine page? That's what subclassing ccProductForm would do
Yes :)
EDIT 2:
Following Tom's first suggestion (Apostrophe CMS: Engine Creation) I was able to extend the aPage table with my extra fields and the Engine is now saving these.
However, the standard aPageTable::getPagesInfo function isn't returning the fields I saved. I assume I'll have to select these separately?
EDIT 3:
aPageTable::retrieveBySlug() will do the job :)
REVISITED
I decided to revisit this and try Tom's second approach..
The other approach (if for whatever reason you don't want extra columns in aPage) is to keep your ccProduct table and fetch the relevant one
I managed to get this working, my ccProductEngine form constructor now looks like this..
class ccProductEngineForm extends ccProductForm
{
public function __construct($aPage = null, $options = array(), $CSRFSecret = null)
{
$page_id = $aPage->getId();
if ($page_id) {
$product = Doctrine_Core::getTable('ccProduct')->findOneByPage_id($page_id);
if ($product) {
$ccProduct = $product;
} else {
$ccProduct = new ccProduct();
}
}
parent::__construct($ccProduct, $options, $CSRFSecret);
}
I hope this helps someone :)
The main thing to remember is that your engine settings form receives a page object as the first parameter to the constructor, and you need to associate whatever your data is with that page object. Usually the engine settings form is a subclass of aPageForm, but it does not have to be. All that is required is that you associate your product object(s) with the page object in some way. Depending on your goals you probably want a refClass that creates a one-to-many relationship between product engine pages and products, and a form for manipulating those relationships.
From your code it is difficult for me to guess what you really want to do. Are you trying to actually create a unique product that has its sole "home" on a product engine page? That's what subclassing ccProductForm would do. Or do you just want to select an existing product from the product table and associate it with each engine page? Or do you want to select one or more products and associate them with the engine page?
Stuffing things into the request object is definitely not the way to go (:
Please clarify and I can help you further.
Tom Boutell, Apostrophe senior developer
There are two approaches you could follow here.
One is to just extend the schema of aPage in your project level config/doctrine/schema.yml file:
aPage:
columns:
synopsis:
type: text
Now every aPage object has a synopsis column, which will be null by default, and your engine settings form can just manipulate that one column. Your engine form subclasses aPageForm. You don't need a constructor at all (the default one will suit you), and your configure() method is just:
$this->useFields(array('synopsis'));
Boom, you have a textarea for the synopsis that appears when the page type is set to this engine. You don't need a ccProduct table at all.
The other approach (if for whatever reason you don't want extra columns in aPage) is to keep your ccProduct table and fetch the relevant one. Your engine form class then does not subclass aPageForm, and your constructor has to use the page passed to it to fetch the related ccProduct object (using a Doctrine relation) or create a new one if there is none yet. This is not difficult, but so far it looks like you can keep it even simpler by just adding a column to aPage.

Resources