I am trying to write a custom output to extend the tt_news-Extension. I have suceeded so far as I have successfully written:
My own extension (via the help of extension builder)
Found a method to output some of my data via GENERIC Markers and TypoScript
What I want to do is:
Read Data from a MySQL Table (from my extensions preferably)
Compare data with a tt_news Column (Column contains VARCHAR "1,2,3,4")
Look for a certain UID (WHERE tt_news.txy7... CONTAINS uid )
Only output the objects found in the list.
Now I know I should probably build a relational database in the end, containing uid, fahrzeug.uid, tt_news.uid , but I'm really trying to figure out a way to output stuff first.
I think I have a basic thinking mistake in there, but I really need to take a break, since im working nearly 6 hours on this now.
Maybe someone could provide me with some directions?
# Output via Generic Markers
temp.fahrzeuge = CONTENT
temp.fahrzeuge {
table = tx_y7fahrzeugdatenbank_domain_model_fahrzeug
wrap = <div class="tx_y7fahrzeuge_ausgabe">|</div>
select {
selectFields = uid,name,beschreibung
# where = tt_news.tx_y7fahrzeugdatenbank_participate CONTAINS uid
}
renderObj = COA
renderObj {
10 = TEXT
10.wrap = <span class="fzname">|</span>
10.field = name
20 = TEXT
20.wrap = <span class="fzdesc">|</span>
20.field = beschreibung
}
}
plugin.tt_news.genericmarkers {
fzparticipate = COA
fzparticipate {
10 = TEXT
10.value = <h2>Fahrzeuge</h2>
20 = CONTENT
20 < temp.fahrzeuge.renderObj
}
#currentnews = plugin.tt_news.currentUid
}
1) add the whole template to your COA not only the renderObj:
fzparticipate = COA
fzparticipate {
10 = TEXT
10.value = <h2>Fahrzeuge</h2>
20 < temp.fahrzeuge
}
2) make sure you have a pid set for the objects you are selecting and that you in some way set the pidInList option within the select. The result will be empty if you don't!:
select {
#set your pid here
pidInList = 35
# selected fields
selectFields=uid
where = 1=1
}
3) You can add where-clauses in 2 ways: Where & andWhere
3.1) andWhere has a cObject which you can set
table = tx_myTable_mapping
select {
#Do not forget the pid!
pidInList = {$plugin.myPlugin.pid}
#did you know that you can use distinct here?
selectFields=DISTINCT(name)
#you can use a COA here as well, for more complex clauses
andWhere.cObject = TEXT
andWhere.cObject {
#This 3 lines come in handy to prevent SQLInjections
#by fully quoting the GET/POST variable
data = GP:myPostVariable
#tell the system for which table it should do the quoting
fullQuoteStr = tx_myTable_mapping
wrap = myTablefield=|
}
}
3.2) where supports data and wrap options
table = tx_myTable_mapping
select {
#you can do joins as well:
join = fe_users on tx_myTable_mapping.fe_user = fe_users.uid
#again with the pageId
pidInList = {$plugin.myPlugin.pid}
selectFields=tx_myTable_mapping.name as MyLabel
#you can set the where in a static way like you did
#or you use the data and wrap options
where.data = TSFE:fe_user|user|uid
where.wrap = (fe_users.uid = | )
}
Related
I have just the following problem, I would like to spend via TYPOScript a specific FE_user in the template, only this does not work, is there a restiktives SQL statement or I use here what wrong? Maybe it's the nesting?
Here is the code:
lib.contactPasswords = COA
lib.contactPasswords.10 = TEXT
lib.contactPasswords.10.value (
<p>User: Safari</p>
)
lib.contactPasswords.20 = CONTENT
lib.contactPasswords.20 {
table = fe_users
select {
max = 1
pidInList = 173
andWhere = username = 'Safari'
}
renderObj = COA
renderObj
{
10 = TEXT
10.field = username
wrap =|<br / >
}
}
lib.contactPasswords.20.wrap = <div>User: |</div>
And the output is the same like:
<p>User: Safari</p>
<div>User:</div>
Desired result:
<p>User: Safari</p>
<div>User: Safari</div>
Can someone explain to me where the mistake is, why the content remains empty?
More Information:
TYPO3 Version: 8.7.19
Using like: <f:cObject typoscriptObjectPath="lib.contactPasswords" /> in Fluid Template
And yes: The User "Safari" exist in the database :)
Are you sure the username is Safari? Usernames are usually all lowercase in TYPO3. If you added it through the backend it will be cast to lowercase. So it would be safari.
You should not have an enter between cObject and {. It should be cObject {
Also andWhere is deprecated since TYPO3 7.1 and removed in TYPO3 8.7. You should use where instead.
For me, this works:
lib.contactPasswords.20 = CONTENT
lib.contactPasswords.20 {
table = fe_users
select {
max = 1
pidInList = 173
where = username = 'safari'
}
renderObj = COA
renderObj {
10 = TEXT
10.field = username
wrap = |<br / >
}
}
'andWhere' reqires, that you also used 'where' in your statement.
But avoid using 'andWhere' since it is deprecated. See https://docs.typo3.org/typo3cms/extensions/core/Changelog/7.1/Deprecation-25112-andWhere.html
After I upgraded TYPO3 from 6.2.9 to 7.6.15 the bodytextfield isn't parsed as HTML anymore. My typoscript creates XML output and I need the bodytext as HTML output.
...
10 = CONTENT
10 {
table = tt_content
select {
where = colPos=0
orderBy = sorting
selectFields = image,header,bodytext
languageField = sys_language_uid
}
wrap = <items>|</items>
renderObj = COA
renderObj {
wrap = <item>|</item>
10 = TEXT
10 {
wrap = <title>|</title>
field=header
}
20 = TEXT
20 {
wrap = <text><![CDATA[ | ]]></text>
field = bodytext
parseFunc = < lib.parseFunc_RTE
}
...
I think the lib.parseFunc_RTE is not working anymore?
Using =< you are referencing to lib.parseFunc_RTE. If it gets deleted somewhere in your Typoscript, the reference will be lost. Check out the Template -> Typoscript if lib.parseFunc_RTE is still present in your Typoscript.
You also can try to not reference it by just copying it
parseFunc < lib.parseFunc_RTE
I working with Database first C# MVC, EF6, LINQ and JSon to try and pass data to both Highcharts and Google Maps for some of my reporting.
If I could add an image I would show you the relevant portion of my model, but sadly I need more reputation to do that...
The portion of the Entity Model I'm concentrating on right now is based on a central Docket that contains a BuildingCode as part of a one-to-many relationship to a building with and address and further relationship to the buildings polygons (for mapping). Dockets are also classified by one or more DocketTypes and thus there is a many-to-many relationship between Dockets and DocketTypes, which is not directly exposed to through the EF.
As an example a Docket which represents an investigation, could be related to the theft of a mobile phone in building A located on Campus X, not only was the cellphone stolen but the assailant also assaulted the victim in order to steal the mobile phone. So there are 2 DocketTypes here 1. Theft of mobile phone and 2. assault. Note: this is fictitious and for illustration purposes only .
One of my fundamental reports requires that I count how many docketTypes affect each building and each campus in a given period. When I display this I also need to show what the DocketTypes are.
I have no end of nightmare trying to find a way to get this right, I keep running into circular reference errors and needing to use explicit conversions when trying to model the data with LINQ so that I can pass a single nested object through JSON to the client side where displaying will occur.
In the below code I am told I need an Explicit conversion:
Cannot implicitly convert type 'Campus_Investigator.ViewModels.DocketTypeViewModel' to 'System.Collections.Generic.IEnumerable<Campus_Investigator.ViewModels.DocketTypeViewModel>'. An explicit conversion exists (are you missing a cast?)
var currentDocketQuery = from d in db.Dockets
from dt in d.DocketTypes
from bp in d.BuildingDetail.BuildingPolygons
where d.OccurrenceStartDate >= datetime && d.BuildingDetail.CampusName == Campus
select new CampusBuildingDocketTypeViewModel()
{
BuildingCode = d.BuildingDetail.BuildingCode,
BuildingName = d.BuildingDetail.BuildingName,
//BuildingPolygons = d.BuildingDetail.BuildingPolygons,
DocketTypes = new DocketTypeViewModel()
{
Category = dt.Category,
SubCategory = dt.SubCategory,
ShortDescription = dt.ShortDescription
}
};
I appreciate any ideas on how I can explicitly convert this or is that a better method I can use and avoid the circular reference error?
You included some redundant part in your query (which performs some inner join). The from bp in d.BuildingDetail.BuildingPolygons is joined in but then is not shown in the result. So it totally does not make sense. There may be duplicated elements in the result due to that. The from dt in d.DocketTypes is wrong joined in, although you need it in the result but because the DocketTypes is output per d in db.Dockets, so it's just simply queried like this:
var currentDocketQuery = from d in db.Dockets
where d.OccurrenceStartDate >= datetime && d.BuildingDetail.CampusName == Campus
select new CampusBuildingDocketTypeViewModel()
{
BuildingCode = d.BuildingDetail.BuildingCode,
BuildingName = d.BuildingDetail.BuildingName,
//BuildingPolygons = d.BuildingDetail.BuildingPolygons,
DocketTypes = d.DocketTypes
};
In fact I can see the commented line //BuildingPolygons = d.BuildingDetail.BuildingPolygons, so if you want to include that, it should also work.
If the DocketTypes has different type of d.DocketTypes, then you need a simple projection like this:
var currentDocketQuery = from d in db.Dockets
where d.OccurrenceStartDate >= datetime && d.BuildingDetail.CampusName == Campus
select new CampusBuildingDocketTypeViewModel()
{
BuildingCode = d.BuildingDetail.BuildingCode,
BuildingName = d.BuildingDetail.BuildingName,
//BuildingPolygons = d.BuildingDetail.BuildingPolygons,
DocketTypes = d.DocketTypes.Select(e => new DocketTypeViewModel()
{
Category = e.Category,
SubCategory = e.SubCategory,
ShortDescription = e.ShortDescription
})
};
I managed to solve this one by using the below. The major hassle with this is the circular referencing that exists in the model. When JSON serializes these, everything falls apart so it takes a lot of transforming to make sure that I only extract what I need. In this case grouped campus and building data (below includes the polygons which where only half commented out in the above) and then the include the detail of the DocketTypes that occurred at each building.
var datetime = DateTime.Now.AddDays(-30);
var campusDocket = from d in db.Dockets
where d.OccurrenceStartDate >= datetime && d.BuildingDetail.CampusName == Campus
group d by new { d.BuildingDetail.CampusName, d.BuildingDetail.BuildingCode, d.BuildingDetail.BuildingName } into groupdata
select new CampusBuildingDocketTypeViewModel
{
BuildingCode = groupdata.Key.BuildingCode,
BuildingName = groupdata.Key.BuildingName,
CampusName = groupdata.Key.CampusName,
Count = groupdata.Count(),
BuildingPolygons = from bp in db.BuildingPolygons
where bp.BuildingCode == groupdata.Key.BuildingCode
select new BuildingPolygonViewModel
{
Accuracy = bp.Accuracy,
BuildingCode = bp.BuildingCode,
PolygonOrder = bp.PolygonOrder,
Latitude = bp.Latitude,
Longitude = bp.Longitude
},
DocketTypes = from doc in db.Dockets
from dt in doc.DocketTypes
where doc.OccurrenceStartDate >= datetime && doc.BuildingCode == groupdata.Key.BuildingCode
select new DocketTypeViewModel
{
Category = dt.Category,
SubCategory = dt.SubCategory,
ShortDescription = dt.ShortDescription
}
};
The Answer again is ViewModels. I'm finding ViewModels seem to solve a lot of problems...
Given this code:
dgIPs.DataSource =
from act in Master.dc.Activities
where act.Session.UID == Master.u.ID
select new
{
Address = act.Session.IP.Address,
Domain = act.Session.IP.Domain,
FirstAccess = act.Session.IP.FirstAccess,
LastAccess = act.Session.IP.LastAccess,
IsSpider = act.Session.IP.isSpider,
NumberProblems = act.Session.IP.NumProblems,
NumberSessions = act.Session.IP.Sessions.Count()
};
How do I pull the Distinct() based on distinct Address only? That is, if I simply add Distinct(), it evaluates the whole row as being distinct and thusly fails to find any duplicates. I want to return exactly one row for each act.Session.IP object.
I've already found this answer, but it seems to be a different situation. Also, Distinct() works fine if I just select act.Session.IP, but it has a column I wish to avoid retrieving and I'd rather not have to do this by manually binding my datagrid columns.
dgIPs.DataSource =
from act in Master.dc.Activities
where act.Session.UID == Master.u.ID
group act by act.Session.IP.Address into g
let ip = g.First().Session.IP
select new
{
Address = ip.Address,
Domain = ip.Domain,
FirstAccess = ip.FirstAccess,
LastAccess = ip.LastAccess,
IsSpider = ip.isSpider,
NumberProblems = ip.NumProblems,
NumberSessions = ip.Sessions.Count()
};
Or:
dgIPs.DataSource =
from act in Master.dc.Activities
where act.Session.UID == Master.u.ID
group act.Session.IP by act.Session.IP.Address into g
let ip = g.First()
select new
{
Address = ip.Address,
Domain = ip.Domain,
FirstAccess = ip.FirstAccess,
LastAccess = ip.LastAccess,
IsSpider = ip.isSpider,
NumberProblems = ip.NumProblems,
NumberSessions = ip.Sessions.Count()
};
One of the overloads of Enumerable.Distinct accepts an IEqualityComparer instance. Simply write a class that implements IEqualityComparer and which only compares the two Address properties.
Unfortunately, you'll have to give a name to the anonymous class you're using.
SELECT ica.CORP_ID, ica.CORP_IDB, ica.ITEM_ID, ica.ITEM_IDB,
ica.EXP_ACCT_NO, ica.SUB_ACCT_NO, ica.PAT_CHRG_NO, ica.PAT_CHRG_PRICE,
ica.TAX_JUR_ID, ica.TAX_JUR_IDB, ITEM_PROFILE.COMDTY_NAME
FROM ITEM_CORP_ACCT ica
,ITEM_PROFILE
WHERE (ica.CORP_ID = 1000)
AND (ica.CORP_IDB = 4051)
AND (ica.ITEM_ID = 1000)
AND (ica.ITEM_IDB = 4051)
AND ica.EXP_ACCT_NO = ITEM_PROFILE.EXP_ACCT_NO
I'm trying basically say since the exp account code is '801500' then the Name should return "Miscellaneous Medic...".
It seems as if what you are showing is not possible. Have you edited the data in the editor??? You are joining using ica.EXP_ACCT_NO = ITEM_PROFILE.EXP_ACCT_NO . Therefore, every entry with EXP_ACCT_NO = 801500, should also have the same COMDTY_NAME.
However, it could be the case that your IDs are not actually numbers and that they are strings with whitespace (801500__ vs 801500 ). But since you are not performing a left-outer join, it would also mean you have an entry in ITEM_PROFILE with the same whitespace.
You also need to properly normalize your table data (unless this is a view) but it still means you have erroneous data.
Try to perform the same query, but using the TRIM function to remove whitespace: https://stackoverflow.com/a/6858168/1688441 .
Example:
SELECT ica.CORP_ID, ica.CORP_IDB, ica.ITEM_ID, ica.ITEM_IDB,
ica.EXP_ACCT_NO, ica.SUB_ACCT_NO, ica.PAT_CHRG_NO, ica.PAT_CHRG_PRICE,
ica.TAX_JUR_ID, ica.TAX_JUR_IDB, ITEM_PROFILE.COMDTY_NAME
FROM ITEM_CORP_ACCT ica
,ITEM_PROFILE
WHERE (ica.CORP_ID = 1000)
AND (ica.CORP_IDB = 4051)
AND (ica.ITEM_ID = 1000)
AND (ica.ITEM_IDB = 4051)
AND trim(ica.EXP_ACCT_NO) = trim(ITEM_PROFILE.EXP_ACCT_NO);