I want to retrieve the instance of a course module - php

tl;dr; trying to get a course module instance via a course module through mysql or the official moodle api. My solution in the end seems rather scrappy though, so i would like some advice.
Hi Moodle people
I am trying to retrieve the corresponding course module instance for each row in mdl_course_modules, a instance in this context would be a single row from mdl_quiz, mdl_wiki or some other course_modules instance.
I have tried a few things, the one i expected to work was:
function get_all_course_modules($course_id) {
global $DB;
$course = $DB->get_record('course', array('id' => $course_id));
$mod_info = get_fast_modinfo($course);
}
I wasn't able to get the course modules instance from $mod_info .
So i tried to do some custom mysql instead,
SELECT course.id, course.fullname, cm.course, cm.section, m.name
FROM mdl_course AS course
JOIN mdl_course_modules AS cm ON cm.course = course.id
JOIN mdl_modules AS m ON m.id = cm.module
JOIN CONCAT('mdl_', m.name) AS module_type ON ...somethingsomething
WHERE course.id = 2;
The sql isn't quite finished, i stumbled on the fact that i dont know all of the different course modules beforehand, that means that i have to use the name of the course_module dynamically to select which instance table i want to join on, or just LEFT JOIN on all of the possible course modules instance tables, but that would take forever and would stop working if someone put in a new course module instance.
Right now im doing the following:
$result = array();
$course_mods = get_course_mods($course_id);
if($course_mods) {
foreach($course_mods as $course_mod) {
$DB->get_records_sql('some sql that selects the instance');
}
}
return $result;
This last piece of code would eventually work, i would be able to able to dynamically create the query from the $course_mod variables such as $course_mod->instance, $course_mod->mod_name etc.
But i think this seems tough. Have any of you guys suceeded in getting the course_module instance in a easier way??
Thanks!!

This is the function i ended up using, to retrieve course module instances, its not so pretty, but whatever.
function get_all_course_modules($course_id) {
global $DB;
$course_mods = get_course_mods($course_id);
$result = array();
if($course_mods) {
foreach($course_mods as $course_mod) {
$course_mod->course_module_instance = $DB->get_record($course_mod->modname, array('id' =>$course_mod->instance ));
$result[$course_mod->id] = $course_mod;
}
}
return $result;
}

Related

How to write a query for sys_categories in TYPO3

I've written a small extension in extbase/fluid and now I'm facing a little problem in the repository.
With my extension you can create item sthat are using system_categories for categorization (similiar to every news extension).
What I want to do is to show all items with category x on page X and all of category y on Page Y.
I know that I have to write the query in my itemRepository.php but I can't get it working, so here' my code of the repository:
public function findSearchForm($limit)
{
$query = $this->createQuery();
$query->getQuerySettings()->setLanguageUid($GLOBALS["TSFE"]->tmpl->setup['config.']['sys_language_uid']);
$query->matching(
$query->like('title','%'.$search.'%')
);
# $query->setOrderings(array('title' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING));
return $query->execute();
}
I tried to extend the query after the "query->like" even with a statement like this
$query->statement("SELECT * FROM sys_category_record_mm WHERE uid_local = '11'")
First of all: How did you enable categorization on your records? Does it correctly work in the backend?
When your TCA is correctly configured for category usage, you can use common repository methods to filter the result. But you have to combine the condition with your "title"-condition using AND.
Try something like this:
public function findSearchForm($limit)
{
$query = $this->createQuery();
$constraints = array();
$yourCategory = 11;
// Your $search-variable seems to be undefined?
//$constraints[] = $query->like('title','%'.$search.'%');
$constraints[] = $query->contains('categories', $yourCategory);
$query->matching(
$query->logicalAnd($constraints)
);
// I think you dont need this...
$query->getQuerySettings()->setLanguageUid($GLOBALS["TSFE"]->tmpl->setup['config.']['sys_language_uid']);
return $query->execute();
}

How to get object of related table

My query using DQL is:
$query = $this->_em->createQuery(
'SELECT v, a
FROM MyBundle:Products v
JOIN v.category a WITH a.id = :id
WHERE v.main = 1'
)
->setMaxResults(1)
->setParameters(array('id' => $id));
$result = $query->getOneOrNullResult();
var_dump($result->getCategory()->getId());
Please, can sombody explain me, why var_dump returns nothing (white page)? I spent a lot of time of solving this, but i dont uderstand, what is the reason of this behavior.
I know, I can select only id of category table I need hole object of category. Query above is just example, that neither ID is returned.
Or is there another way to get object of related table?
First of all, is the entity's name really Products and not Product?
Second, check that the inverse mapping is set up properly for category.
I just tried a simple example with the exact same use case, and it works fine.
$em = $this->get('doctrine')->getEntityManager();
$query = $em->createQuery(
'SELECT p, c
FROM TestTestBundle:P p
JOIN p.children c WITH c.id = :id
WHERE p.main = 1'
)
->setMaxResults(1)
->setParameters(array('id' => $id));
if (null !== $result = $query->getOneOrNullResult()) {
foreach ($result->getChildren() as $child) {
var_dump($child->getTitle());
}
}
Do as NHG said and enable error reporting so that we could get a hint of what is wrong.
Here's the ORM mapping for the two entities used.
The Parent
class P
{
/**
* #ORM\OneToMany(targetEntity="Test\TestBundle\Entity\C", mappedBy="parent")
*/
private $children;
public function getChildren()
{
return $this->children;
}
The Child
class C
{
/**
* #ORM\ManyToOne(targetEntity="Test\TestBundle\Entity\P", inversedBy="children")
*/
private $parent;
Thanks for all your responses. I found the problem, which was in my dumps. But only in case, when I dumped big objects as was my entity with relations. Skript stoped on it, or something and never continue. So when I removed these dumps, it works correctly.
Maybe, workable solution, for dumping large objects, could be in Enterx's comment, but I could't try it, becouse my app is on remote server, where I have no access to php.ini.

Zend framework fetchall function

I've got below function in my Organisation model.
public function getOrganisations($where=null,$order='name ASC',$offset=null,$limit=null){
$Result = $this->fetchAll($where,$order,$limit,$offset);
if (!$Result){
return array();
}
return $Result->toArray();
}
but How can I include my organisation_types model so I can left join to organisation_type_id in organisation table?
This is the core of the argument in favor of using the data mapper pattern.
With the structure you seem to be using in your example you'll have huge trouble trying pass the organisation_types object into your Organisation model. You can however do a join in your query to join to the organisation_types table, but joining on the object is not likely to be reasonable.
to join on the organisation_types table:
//assuming this is a DbTable model that extends Zend_Db_Table_Abstract
function getOrganisations($where=null,$order='name ASC',$offset=null,$limit=null){
$select = $this->select()->setIntegrityCheck(FALSE);//This locks the table to allow joins
$select->joinLeft('organisation_types', 'organisation_types.id = organisation.organisation_type_id');//This will join the tables with all feilds, use the join type you like.
if (!is_null($where) {
$select->where($where);
}
if (!is_null($order) {
$select->order($order);
}
if (!is_null($offset) {
$select->limit(null,$offset);//offset is second arg in limit() in select()
}
if (!is_null($limit) {
$select->limit($limit);
}
$Result = $this->fetchAll($select);
if (!$Result){
return array();
}
return $Result->toArray();
}
This should give you an idea of how a table join would work. If you want to use the objects you'll need to begin again with a different structure.
I found a couple of good tutorials on PHPMaster that helped me get my head around the data mappers and domain models.
Building A Domain Model, Introduction
Integrating data mappers
Also The online book Survive The Deepend has a good example of the data mapper pattern and how to test it.
Good Luck...
Maybe using Zend_Db_Select with joinLeft() would be more appropriate:
http://framework.zend.com/manual/en/zend.db.select.html#zend.db.select.building.join

OOP php method - pass variables in or get from inside object

I am new to OOP and have written a products class. All is working fine but I am unsure which of the below version of a method within this class is best?
The first gets the variables from within the object and the second passes the variables into the class. Both work. I originally had it as the first version but things seems to be running slow and then changed it to the second.
public function getProductURLstart(){
$select = "SELECT l.URL, p.id FROM logins AS l
INNER JOIN Pages AS p ON l.id = p.clientID
WHERE l.id = '$this->skID' AND p.productPage = 1";
$res = mssql_query($select);
$r = mssql_fetch_row($res);
$url = trim($r[0]);
$page_id = $r[1];
return $url .'/index.aspx?pageID='. $page_id . '&prodID=$this->prodID';
}
OR
static function getProductURLstart($skID, $prodId){
$select = "SELECT l.URL, p.id FROM logins AS l
INNER JOIN Pages AS p ON l.id = p.clientID
WHERE l.id = '$skID' AND p.productPage = 1";
$res = mssql_query($select);
$r = mssql_fetch_row($res);
$url = trim($r[0]);
$page_id = $r[1];
return $url .'/index.aspx?pageID='. $page_id . '&prodID=$prodId';
}
If the instance of this class is for a single product, then use the first method,as there would be no reason to pass it in as parameters if you have them set when you construct the class.
Otherwise, if this is for more than on product, then the second method would be your best choice. As you will not have to call and set methods for the skID and prodID every time you need to get a product URL.
It depends, if you plan to give models some functionality like making them a little bit like active records, you can put the functionality in the class and use the class' members. Besides, do you have a good reason to use static functions? If you want to apply OOP, you have to give responsibilities to meaningful classes, a model should not both get data and do the redirection.
I'll be with the first. I always develop my app trying to use the less static methods I can and always using attributes, avoiding sending them by function parameters.

Zend_Db_Select order by random, compatible in mssql / mysql

Alright here's the situation, I have an application written in the Zend_Framework, that is compatible with both MySQL and MSSQL as the backend. Now, ZF is pretty good at solving a lot of the SQL discrepancies/differences between the two languages, but I still have yet to figure this one out.
The objective is to select 1 random record from the table, which is an extremely simple statement.
Here's a select statement for example:
$sql = $db->select()
->from("table")
->order("rand()")
->limit(1);
This works perfectly for the MySQL database tables, because the sql for MySQL is as follows:
SELECT `table`.* FROM `table` ORDER BY rand() ASC
Now MSSQL on the other hand, uses the newid() function to do randomizing.
Is there some sort of helper I can pass into the order() function in order to make it realize that it has to use the proper ordering? I searched the documentation and on the zfforums, found a few tips, but nothing solid.
One of the things I did find was:
ORDER BY RANDOM() not working - ZFForums.com
They are using the following:
$res = $db->fetchAll(
'SELECT * FROM table ORDER BY :random',
array('random' => new Zend_Db_Expr('RANDOM()')
);
It works... but I am not looking to build my select statement by typing it out and doing a replace on the string, I am trying to keep it in the same Zend_Db_Select object. I also have tried passing in the Zend_Db_Expr('RANDOM()') into the ->order() on the statement, and it fails. He also posts a theoretical solution to finding the answer, but I am not looking to rewrite the function this is within, modifying the $db->fetch() call.
Any ideas?
You could quickly abstract the function to a table - who knows which adapter it is using:
class MyTable extends Zend_Db_Table_Abstract {
public function randomSelect($select=null) {
if ($select === null) $select = $this->select();
if (!$select instanceOf Zend_Db_Select) $select = $this->select($select);
$adapter = $this->getAdapter();
if ($adapter instanceOf Zend_Db_Adapter_Mysqli) {
$select->order(new Zend_Db_Expr('RAND()'));
} else if ($adapter instanceOf Zend_Db_Adapter_Dblib) {
$select->order(new Zend_Db_Expr('NEWID()'));
} else {
throw new Exception('Unknown adapter in MyTable');
}
return $select;
}
}
$someSelect = $table->select();
// add it to an existing select
$table->randomSelect($someSelect);
// or create one from scratch
$select = $table->randomSelect();
Also, I found an article somewhere which I lost that recommended trying something like:
$select->order(new Zend_Db_Expr('0*`id`+RAND()));
to subvert MSSQL's query optimizer and trick it into calculating a new value for each row.
I would create class My_Db_Expr_Rand extends Zend_Db_Expr. Bassed on the adapter I would return either one or the other.

Categories